Pārlūkot izejas kodu

Merge branch 'master' of http://10.1.235.20:3000/ipu/android-share.git

huangbo 8 gadi atpakaļ
vecāks
revīzija
54bef00831
31 mainītis faili ar 0 papildinājumiem un 1584 dzēšanām
  1. 0 10
      ipu-pathmenu/.classpath
  2. 0 33
      ipu-pathmenu/.project
  3. 0 29
      ipu-pathmenu/AndroidManifest.xml
  4. 0 6
      ipu-pathmenu/README.md
  5. 0 20
      ipu-pathmenu/proguard-project.txt
  6. BIN
      ipu-pathmenu/res/drawable-hdpi/composer_button.png
  7. BIN
      ipu-pathmenu/res/drawable-hdpi/composer_camera.png
  8. BIN
      ipu-pathmenu/res/drawable-hdpi/composer_close.png
  9. BIN
      ipu-pathmenu/res/drawable-hdpi/composer_icn_plus.png
  10. BIN
      ipu-pathmenu/res/drawable-hdpi/composer_music.png
  11. BIN
      ipu-pathmenu/res/drawable-hdpi/composer_place.png
  12. BIN
      ipu-pathmenu/res/drawable-hdpi/composer_sleep.png
  13. BIN
      ipu-pathmenu/res/drawable-hdpi/composer_thought.png
  14. BIN
      ipu-pathmenu/res/drawable-hdpi/composer_with.png
  15. 0 20
      ipu-pathmenu/res/drawable/button.xml
  16. 0 28
      ipu-pathmenu/res/layout/activity_float.xml
  17. 0 29
      ipu-pathmenu/res/layout/float_menu.xml
  18. 0 5
      ipu-pathmenu/res/menu/main.xml
  19. 0 11
      ipu-pathmenu/res/values-v11/styles.xml
  20. 0 12
      ipu-pathmenu/res/values-v14/styles.xml
  21. 0 10
      ipu-pathmenu/res/values-w820dp/dimens.xml
  22. 0 19
      ipu-pathmenu/res/values/attrs.xml
  23. 0 9
      ipu-pathmenu/res/values/dimens.xml
  24. 0 7
      ipu-pathmenu/res/values/strings.xml
  25. 0 20
      ipu-pathmenu/res/values/styles.xml
  26. 0 515
      ipu-pathmenu/src/com/ai/ipu/ipu_pathmenu/PathMenu.java
  27. 0 39
      ipu-pathmenu/src/com/ai/ipu/ipu_pathmenu/PathMenuActivity.java
  28. 0 495
      ipu-pathmenu/src/com/ai/ipu/ipu_pathmenu/PathMenuLayout.java
  29. 0 94
      ipu-pathmenu/src/com/ai/ipu/ipu_pathmenu/PathMenuService.java
  30. 0 123
      ipu-pathmenu/src/com/ai/ipu/ipu_pathmenu/RotateAndTranslateAnimation.java
  31. 0 50
      ipu-pathmenu/src/com/ai/ipu/ipu_pathmenu/func/MobilePathMenu.java

+ 0 - 10
ipu-pathmenu/.classpath

@ -1,10 +0,0 @@
1
<?xml version="1.0" encoding="UTF-8"?>
2
<classpath>
3
	<classpathentry kind="src" path="src"/>
4
	<classpathentry kind="src" path="gen"/>
5
	<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/>
6
	<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.DEPENDENCIES"/>
7
	<classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
8
	<classpathentry combineaccessrules="false" kind="src" path="/wade-mobile"/>
9
	<classpathentry kind="output" path="bin/classes"/>
10
</classpath>

+ 0 - 33
ipu-pathmenu/.project

@ -1,33 +0,0 @@
1
<?xml version="1.0" encoding="UTF-8"?>
2
<projectDescription>
3
	<name>ipu-pathmenu</name>
4
	<comment></comment>
5
	<projects>
6
	</projects>
7
	<buildSpec>
8
		<buildCommand>
9
			<name>com.android.ide.eclipse.adt.ResourceManagerBuilder</name>
10
			<arguments>
11
			</arguments>
12
		</buildCommand>
13
		<buildCommand>
14
			<name>com.android.ide.eclipse.adt.PreCompilerBuilder</name>
15
			<arguments>
16
			</arguments>
17
		</buildCommand>
18
		<buildCommand>
19
			<name>org.eclipse.jdt.core.javabuilder</name>
20
			<arguments>
21
			</arguments>
22
		</buildCommand>
23
		<buildCommand>
24
			<name>com.android.ide.eclipse.adt.ApkBuilder</name>
25
			<arguments>
26
			</arguments>
27
		</buildCommand>
28
	</buildSpec>
29
	<natures>
30
		<nature>com.android.ide.eclipse.adt.AndroidNature</nature>
31
		<nature>org.eclipse.jdt.core.javanature</nature>
32
	</natures>
33
</projectDescription>

+ 0 - 29
ipu-pathmenu/AndroidManifest.xml

@ -1,29 +0,0 @@
1
<?xml version="1.0" encoding="utf-8"?>
2
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
3
    package="com.ai.ipu.ipu_pathmenu"
4
    android:versionCode="1"
5
    android:versionName="1.0" >
6
7
    <uses-sdk
8
        android:minSdkVersion="15"
9
        android:targetSdkVersion="21" />
10
11
    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
12
13
    <application
14
        android:allowBackup="true"
15
        android:label="@string/app_name"
16
        android:theme="@style/AppTheme" >
17
        <activity
18
            android:name=".PathMenuActivity"
19
            android:label="@string/app_name" >
20
            <intent-filter>
21
                <action android:name="android.intent.action.MAIN" />
22
23
                <category android:name="android.intent.category.LAUNCHER" />
24
            </intent-filter>
25
        </activity>
26
        <service android:name="com.ai.ipu.ipu_pathmenu.PathMenuService"></service>
27
    </application>
28
29
</manifest>

+ 0 - 6
ipu-pathmenu/README.md

@ -1,6 +0,0 @@
1
参考自 https://github.com/daCapricorn/ArcMenu
2
3
增加悬浮功能、拖拽时能更改子菜单方向。
4
5
感谢 @yiming 的帮助~~~
6
https://github.com/fanOfDemo

+ 0 - 20
ipu-pathmenu/proguard-project.txt

@ -1,20 +0,0 @@
1
# To enable ProGuard in your project, edit project.properties
2
# to define the proguard.config property as described in that file.
3
#
4
# Add project specific ProGuard rules here.
5
# By default, the flags in this file are appended to flags specified
6
# in ${sdk.dir}/tools/proguard/proguard-android.txt
7
# You can edit the include path and order by changing the ProGuard
8
# include property in project.properties.
9
#
10
# For more details, see
11
#   http://developer.android.com/guide/developing/tools/proguard.html
12
13
# Add any project specific keep options here:
14
15
# If your project uses WebView with JS, uncomment the following
16
# and specify the fully qualified class name to the JavaScript interface
17
# class:
18
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
19
#   public *;
20
#}

BIN
ipu-pathmenu/res/drawable-hdpi/composer_button.png


BIN
ipu-pathmenu/res/drawable-hdpi/composer_camera.png


BIN
ipu-pathmenu/res/drawable-hdpi/composer_close.png


BIN
ipu-pathmenu/res/drawable-hdpi/composer_icn_plus.png


BIN
ipu-pathmenu/res/drawable-hdpi/composer_music.png


BIN
ipu-pathmenu/res/drawable-hdpi/composer_place.png


BIN
ipu-pathmenu/res/drawable-hdpi/composer_sleep.png


BIN
ipu-pathmenu/res/drawable-hdpi/composer_thought.png


BIN
ipu-pathmenu/res/drawable-hdpi/composer_with.png


+ 0 - 20
ipu-pathmenu/res/drawable/button.xml

@ -1,20 +0,0 @@
1
<?xml version="1.0" encoding="utf-8"?>
2
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
3
        <!--点击背景-->  
4
        <item android:state_pressed="true">  
5
            <shape>  
6
                 <!--色值-->  
7
                <solid android:color="#B0E0E6" />  
8
                <!--圆角-->  
9
                <corners android:radius="10dp" />  
10
            </shape>  
11
        </item>  
12
        <!--默认背景-->  
13
        <item>  
14
            <shape>  
15
                <solid android:color="#D1EEEE" />  
16
                <corners android:radius="10dp" />  
17
            </shape>  
18
        </item>  
19
20
</selector>

+ 0 - 28
ipu-pathmenu/res/layout/activity_float.xml

@ -1,28 +0,0 @@
1
<?xml version="1.0" encoding="utf-8"?>
2
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
3
    xmlns:arc="http://schemas.android.com/apk/res-auto"
4
    android:layout_width="fill_parent"
5
    android:layout_height="fill_parent" >
6
7
    <LinearLayout
8
        android:layout_width="fill_parent"
9
        android:layout_height="wrap_content"
10
        android:orientation="vertical" >
11
12
        <Button
13
            android:id="@+id/btnOpenFloat"
14
            android:layout_width="wrap_content"
15
            android:layout_height="wrap_content"
16
            android:layout_weight="1"
17
            android:text="open float menu" />
18
19
        <Button
20
            android:id="@+id/btnCloseFloat"
21
            android:layout_width="wrap_content"
22
            android:layout_height="wrap_content"
23
            android:layout_weight="1"
24
            android:text="close float menu" />
25
26
    </LinearLayout>
27
28
</ScrollView>

+ 0 - 29
ipu-pathmenu/res/layout/float_menu.xml

@ -1,29 +0,0 @@
1
<?xml version="1.0" encoding="utf-8"?>
2
<merge xmlns:android="http://schemas.android.com/apk/res/android" >
3
4
    <com.ai.ipu.ipu_pathmenu.PathMenuLayout
5
        xmlns:custom="http://schemas.android.com/apk/res-auto"
6
        android:id="@+id/item_layout"
7
        android:layout_width="wrap_content"
8
        android:layout_height="wrap_content"
9
        android:layout_centerInParent="true"
10
        custom:fromDegrees="270.0"
11
        custom:toDegrees="360.0" />
12
13
    <FrameLayout
14
        android:id="@+id/control_layout"
15
        android:layout_width="wrap_content"
16
        android:layout_height="wrap_content"
17
        android:layout_centerInParent="true"
18
        android:background="@drawable/composer_button" >
19
20
        <ImageView
21
            android:id="@+id/control_hint"
22
            android:layout_width="wrap_content"
23
            android:layout_height="wrap_content"
24
            android:layout_gravity="center"
25
            android:duplicateParentState="true"
26
            android:src="@drawable/composer_icn_plus" />
27
    </FrameLayout>
28
29
</merge>

+ 0 - 5
ipu-pathmenu/res/menu/main.xml

@ -1,5 +0,0 @@
1
<menu xmlns:android="http://schemas.android.com/apk/res/android"
2
    xmlns:tools="http://schemas.android.com/tools"
3
    tools:context="com.ai.ipu.ipu_pathmenu.MainActivity" >
4
5
</menu>

+ 0 - 11
ipu-pathmenu/res/values-v11/styles.xml

@ -1,11 +0,0 @@
1
<resources>
2
3
    <!--
4
        Base application theme for API 11+. This theme completely replaces
5
        AppBaseTheme from res/values/styles.xml on API 11+ devices.
6
    -->
7
    <style name="AppBaseTheme" parent="android:Theme.Holo.Light">
8
        <!-- API 11 theme customizations can go here. -->
9
    </style>
10
11
</resources>

+ 0 - 12
ipu-pathmenu/res/values-v14/styles.xml

@ -1,12 +0,0 @@
1
<resources>
2
3
    <!--
4
        Base application theme for API 14+. This theme completely replaces
5
        AppBaseTheme from BOTH res/values/styles.xml and
6
        res/values-v11/styles.xml on API 14+ devices.
7
    -->
8
    <style name="AppBaseTheme" parent="android:Theme.Holo.Light.DarkActionBar">
9
        <!-- API 14 theme customizations can go here. -->
10
    </style>
11
12
</resources>

+ 0 - 10
ipu-pathmenu/res/values-w820dp/dimens.xml

@ -1,10 +0,0 @@
1
<resources>
2
3
    <!--
4
         Example customization of dimensions originally defined in res/values/dimens.xml
5
         (such as screen margins) for screens with more than 820dp of available width. This
6
         would include 7" and 10" devices in landscape (~960dp and ~1280dp respectively).
7
    -->
8
    <dimen name="activity_horizontal_margin">64dp</dimen>
9
10
</resources>

+ 0 - 19
ipu-pathmenu/res/values/attrs.xml

@ -1,19 +0,0 @@
1
<?xml version="1.0" encoding="UTF-8"?>
2
<resources>
3
    <attr name="fromDegrees" format="float|reference" />
4
    <attr name="toDegrees" format="float|reference" />
5
    <attr name="childSize" format="dimension|reference" />
6
7
	<declare-styleable name="ArcLayout">
8
        <attr name="fromDegrees"/>
9
        <attr name="toDegrees"/>
10
        <attr name="childSize"/>
11
	</declare-styleable>
12
13
    <declare-styleable name="ArcMenu">
14
        <attr name="fromDegrees"/>
15
        <attr name="toDegrees"/>
16
        <attr name="childSize"/>
17
    </declare-styleable>
18
	
19
</resources>

+ 0 - 9
ipu-pathmenu/res/values/dimens.xml

@ -1,9 +0,0 @@
1
<resources>
2
3
    <!-- Default screen margins, per the Android Design guidelines. -->
4
    <dimen name="activity_horizontal_margin">16dp</dimen>
5
    <dimen name="activity_vertical_margin">16dp</dimen>
6
	<item name="menuFromDegrees" format="float" type="dimen">180.0</item>
7
    <item name="menuToDegrees" format="float" type="dimen">360.0</item>
8
    <dimen name="menuChildSize">30dp</dimen>
9
</resources>

+ 0 - 7
ipu-pathmenu/res/values/strings.xml

@ -1,7 +0,0 @@
1
<?xml version="1.0" encoding="utf-8"?>
2
<resources>
3
4
    <string name="app_name">ipu_pathmenu</string>
5
    <string name="openService">打开服务</string>
6
7
</resources>

+ 0 - 20
ipu-pathmenu/res/values/styles.xml

@ -1,20 +0,0 @@
1
<resources>
2
3
    <!--
4
        Base application theme, dependent on API level. This theme is replaced
5
        by AppBaseTheme from res/values-vXX/styles.xml on newer devices.
6
    -->
7
    <style name="AppBaseTheme" parent="android:Theme.Light">
8
        <!--
9
            Theme customizations available in newer API levels can go in
10
            res/values-vXX/styles.xml, while customizations related to
11
            backward-compatibility can go here.
12
        -->
13
    </style>
14
15
    <!-- Application theme. -->
16
    <style name="AppTheme" parent="AppBaseTheme">
17
        <!-- All customizations that are NOT specific to a particular API-level can go here. -->
18
    </style>
19
20
</resources>

+ 0 - 515
ipu-pathmenu/src/com/ai/ipu/ipu_pathmenu/PathMenu.java

@ -1,515 +0,0 @@
1
package com.ai.ipu.ipu_pathmenu;
2
3
import android.content.Context;
4
import android.content.res.TypedArray;
5
import android.graphics.PixelFormat;
6
import android.os.Build;
7
import android.util.AttributeSet;
8
import android.util.DisplayMetrics;
9
import android.util.Log;
10
import android.view.Gravity;
11
import android.view.LayoutInflater;
12
import android.view.MotionEvent;
13
import android.view.View;
14
import android.view.View.OnTouchListener;
15
import android.view.ViewTreeObserver;
16
import android.view.ViewTreeObserver.OnGlobalLayoutListener;
17
import android.view.WindowManager;
18
import android.view.animation.AlphaAnimation;
19
import android.view.animation.Animation;
20
import android.view.animation.Animation.AnimationListener;
21
import android.view.animation.AnimationSet;
22
import android.view.animation.DecelerateInterpolator;
23
import android.view.animation.RotateAnimation;
24
import android.view.animation.ScaleAnimation;
25
import android.widget.FrameLayout;
26
import android.widget.ImageView;
27
28
/**
29
 * 自定义菜单
30
 * 
31
 * @author 何凌波
32
 *
33
 */
34
public class PathMenu extends FrameLayout implements OnTouchListener {
35
	private PathMenuLayout mPathMenuLayout;
36
	private FrameLayout controlLayout;
37
	private ImageView mHintView;// 中心按钮显示图片
38
	private WindowManager mWindowManager;// 当前view的窗口管理器
39
	// WindowMananger的params,控制这个值可以将自定义的view设置到窗口管理器中
40
	private WindowManager.LayoutParams mWmParams;
41
	private float mTouchStartX;// 记录首次按下的位置x
42
	private float mTouchStartY;// 记录首次按下的位置y
43
44
	private int mScreenWidth;// 屏幕宽度
45
	private int mScreenHeight;// 屏幕高度
46
	private boolean mDraging;// 是否拖动中
47
	private Context mContext;
48
49
	private int position;// 按钮的位置
50
	public static final int LEFT_TOP = 1;
51
	public static final int CENTER_TOP = 2;
52
	public static final int RIGHT_TOP = 3;
53
	public static final int LEFT_CENTER = 4;
54
	public static final int CENTER = 5;
55
	public static final int RIGHT_CENTER = 6;
56
	public static final int LEFT_BOTTOM = 7;
57
	public static final int CENTER_BOTTOM = 8;
58
	public static final int RIGHT_BOTTOM = 9;
59
60
	public PathMenu(Context context) {
61
		super(context);
62
		this.mContext = context;
63
		init(mContext);
64
	}
65
66
	public PathMenu(Context context, AttributeSet attrs) {
67
		super(context, attrs);
68
		this.mContext = context;
69
		init(mContext);
70
		applyAttrs(attrs);
71
	}
72
73
	/**
74
	 * 初始化中心按钮布局,加载布局文件,设置触摸事件
75
	 * 
76
	 * @param context
77
	 */
78
	private void init(Context context) {
79
		LayoutInflater li = (LayoutInflater) context
80
				.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
81
		li.inflate(R.layout.float_menu, this);
82
		mWindowManager = (WindowManager) context
83
				.getSystemService(Context.WINDOW_SERVICE);// 获取系统的窗口服务
84
		DisplayMetrics dm = new DisplayMetrics();
85
		mWindowManager.getDefaultDisplay().getMetrics(dm);
86
		mScreenWidth = dm.widthPixels;// 根据当前屏幕信息拿到屏幕的宽高
87
		mScreenHeight = dm.heightPixels - getStatusBarHeight();
88
		this.mWmParams = new WindowManager.LayoutParams();// 获取窗口参数
89
90
		if (Build.VERSION.SDK_INT <= 19) {
91
			mWmParams.type = WindowManager.LayoutParams.TYPE_TOAST;// 等于API19或API19以下需要指定窗口参数type值为TYPE_TOAST才可以作为悬浮控件显示出来
92
		} else {
93
			mWmParams.type = WindowManager.LayoutParams.TYPE_PHONE;// API19以上侧只需指定为TYPE_PHONE即可
94
		}
95
		mWmParams.format = PixelFormat.RGBA_8888;// 当前窗口的像素格式为RGBA_8888,即为最高质量
96
97
		// NOT_FOCUSABLE可以是悬浮控件可以响应事件,LAYOUT_IN_SCREEN可以指定悬浮球指定在屏幕内,部分虚拟按键的手机,虚拟按键隐藏时,虚拟按键的位置则属于屏幕内,此时悬浮球会出现在原虚拟按键的位置
98
		mWmParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
99
		// 默认指定位置在屏幕的左上方,可以根据需要自己修改
100
		mWmParams.gravity = Gravity.LEFT | Gravity.TOP;
101
		position = 1;
102
		// 默认指定的横坐标为屏幕一半
103
		mWmParams.x = mScreenWidth / 2;
104
		// 默认指定的纵坐标为屏幕高度的一半,这里只是大概约束,因为上的flags参数限制,悬浮球不会出现在屏幕外
105
		mWmParams.y = mScreenHeight / 2;
106
107
		// 宽度指定为内容自适应
108
		mWmParams.width = LayoutParams.WRAP_CONTENT;
109
		mWmParams.height = LayoutParams.WRAP_CONTENT;
110
111
		mPathMenuLayout = (PathMenuLayout) findViewById(getIdByName(context, "id", "item_layout"));
112
		
113
		controlLayout = (FrameLayout) findViewById(getIdByName(context, "id", "control_layout"));
114
		controlLayout.setClickable(true);
115
		controlLayout.setOnTouchListener(this);
116
117
		mHintView = (ImageView) findViewById(getIdByName(context, "id", "control_hint"));
118
119
		mWindowManager.addView(this, mWmParams);
120
121
		controlLayout.setOnClickListener(new OnClickListener() {
122
			@Override
123
			public void onClick(View v) {
124
				 if (!mDraging) {
125
	                    if (mPathMenuLayout.isExpanded()) {
126
	                        mPathMenuLayout.switchState(true, position);
127
	                        mHintView
128
	                                .startAnimation(createHintSwitchAnimation(true));
129
	                    } else {
130
	                        mHintView
131
	                                .startAnimation(createHintSwitchAnimation(false));
132
	                        mPathMenuLayout.setVisibility(VISIBLE);
133
	                        mPathMenuLayout.setPosition(position);
134
	                        postDelayed(new Runnable() {
135
	                            @Override
136
	                            public void run() {
137
	                                mPathMenuLayout.switchState(true);
138
	                            }
139
	                        }, 60);
140
141
	                    }
142
	                }
143
			}
144
		});
145
		// 必须在绘制完成后才能获得控件的宽高
146
		ViewTreeObserver vto = controlLayout.getViewTreeObserver();
147
		vto.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
148
			@Override
149
			public void onGlobalLayout() {
150
				controlLayout.getViewTreeObserver()
151
						.removeGlobalOnLayoutListener(this);
152
				int controlLayoutWidth = controlLayout.getWidth();
153
				mPathMenuLayout.setChildSize(controlLayoutWidth);
154
			}
155
		});
156
	}
157
158
	
159
	public static int getIdByName(Context context, String className, String name) {  
160
        String packageName = context.getPackageName();  
161
        Class r = null;  
162
        int id = 0;  
163
  
164
        try {  
165
            r = Class.forName(packageName + ".R");  
166
            Class[] classes = r.getClasses();  
167
            Class desireClass = null;  
168
  
169
            for (int i = 0; i < classes.length; ++i) {  
170
                if (classes[i].getName().split("\\$")[1].equals(className)) {  
171
                    desireClass = classes[i];  
172
                    break;  
173
                }  
174
            }  
175
  
176
            if (desireClass != null) {  
177
                id = desireClass.getField(name).getInt(desireClass);  
178
            }  
179
        } catch (ClassNotFoundException e) {  
180
            e.printStackTrace();  
181
        } catch (IllegalArgumentException e) {  
182
            e.printStackTrace();  
183
        } catch (SecurityException e) {  
184
            e.printStackTrace();  
185
        } catch (IllegalAccessException e) {  
186
            e.printStackTrace();  
187
        } catch (NoSuchFieldException e) {  
188
            e.printStackTrace();  
189
        }  
190
  
191
        return id;  
192
    }  
193
	/**
194
	 * 应用自定义属性,设置弧度、子菜单项大小
195
	 * 
196
	 * @param attrs
197
	 */
198
	private void applyAttrs(AttributeSet attrs) {
199
		if (attrs != null) {
200
			TypedArray a = getContext().obtainStyledAttributes(attrs,
201
					R.styleable.ArcLayout, 0, 0);
202
203
			float fromDegrees = a.getFloat(R.styleable.ArcLayout_fromDegrees,
204
					PathMenuLayout.DEFAULT_FROM_DEGREES);
205
			float toDegrees = a.getFloat(R.styleable.ArcLayout_toDegrees,
206
					PathMenuLayout.DEFAULT_TO_DEGREES);
207
			mPathMenuLayout.setArc(fromDegrees, toDegrees);
208
			a.recycle();
209
		}
210
	}
211
212
	/**
213
	 * 添加子菜单项和对应的点击事件
214
	 * 
215
	 * @param item
216
	 * @param listener
217
	 */
218
	public void addItem(View item, OnClickListener listener) {
219
		mPathMenuLayout.addView(item);
220
		item.setOnClickListener(getItemClickListener(listener));
221
	}
222
223
	/**
224
	 * 子菜单项的点击事件
225
	 * 
226
	 * @param listener
227
	 * @return
228
	 */
229
	private OnClickListener getItemClickListener(final OnClickListener listener) {
230
		return new OnClickListener() {
231
			// 点击,child放大,其他child消失
232
			@Override
233
			public void onClick(final View viewClicked) {
234
				Animation animation = bindItemAnimation(viewClicked, true, 400);
235
				animation.setAnimationListener(new AnimationListener() {
236
237
					@Override
238
					public void onAnimationStart(Animation animation) {
239
240
					}
241
242
					@Override
243
					public void onAnimationRepeat(Animation animation) {
244
245
					}
246
247
					@Override
248
					public void onAnimationEnd(Animation animation) {
249
						postDelayed(new Runnable() {
250
251
							@Override
252
							public void run() {
253
								itemDidDisappear();
254
							}
255
						}, 0);
256
					}
257
				});
258
				// child 被点击的时候,自身放大,其他child消失的效果
259
				final int itemCount = mPathMenuLayout.getChildCount();
260
				for (int i = 0; i < itemCount; i++) {
261
					View item = mPathMenuLayout.getChildAt(i);
262
					if (viewClicked != item) {
263
						bindItemAnimation(item, false, 300);
264
					}
265
				}
266
				// 中心控制点动画 旋转
267
				mPathMenuLayout.invalidate();
268
				mHintView.startAnimation(createHintSwitchAnimation(true));
269
270
				if (listener != null) {
271
					listener.onClick(viewClicked);
272
				}
273
			}
274
		};
275
	}
276
277
	/**
278
	 * 绑定子菜单项动画
279
	 * 
280
	 * @param child
281
	 * @param isClicked
282
	 * @param duration
283
	 * @return
284
	 */
285
	private Animation bindItemAnimation(final View child,
286
			final boolean isClicked, final long duration) {
287
		Animation animation = createItemDisapperAnimation(duration, isClicked);
288
		child.setAnimation(animation);
289
290
		return animation;
291
	}
292
293
	/**
294
	 * 子菜单项关闭时消失
295
	 */
296
	private void itemDidDisappear() {
297
		final int itemCount = mPathMenuLayout.getChildCount();
298
		for (int i = 0; i < itemCount; i++) {
299
			View item = mPathMenuLayout.getChildAt(i);
300
			item.clearAnimation();
301
		}
302
		mPathMenuLayout.switchState(false, position);
303
	}
304
305
	/**
306
	 * 子菜单消失动画
307
	 * 
308
	 * @param duration
309
	 * @param isClicked
310
	 * @return
311
	 */
312
	private static Animation createItemDisapperAnimation(final long duration,
313
			final boolean isClicked) {
314
		AnimationSet animationSet = new AnimationSet(true);
315
		// 放大缩小动画,isClicked 为true,放大两倍;为false,缩小至0
316
		animationSet.addAnimation(new ScaleAnimation(1.0f, isClicked ? 2.0f
317
				: 0.0f, 1.0f, isClicked ? 2.0f : 0.0f,
318
				Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,
319
				0.5f));
320
		// Alpha改为0,child消失
321
		animationSet.addAnimation(new AlphaAnimation(1.0f, 0.0f));
322
323
		animationSet.setDuration(duration);
324
		animationSet.setInterpolator(new DecelerateInterpolator());
325
		animationSet.setFillAfter(true);
326
327
		return animationSet;
328
	}
329
330
	
331
	/**
332
	 * 中心按钮点击旋转45度动画
333
	 * 
334
	 * @param expanded
335
	 * @return
336
	 */
337
	private static Animation createHintSwitchAnimation(final boolean expanded) {
338
		Animation animation = new RotateAnimation(expanded ? 45 : 0,
339
				expanded ? 0 : 45, Animation.RELATIVE_TO_SELF, 0.5f,
340
				Animation.RELATIVE_TO_SELF, 0.5f);
341
		animation.setStartOffset(0);
342
		animation.setDuration(100);
343
		animation.setInterpolator(new DecelerateInterpolator());
344
		animation.setFillAfter(true);
345
346
		return animation;
347
	}
348
349
	/**
350
	 * 触摸事件
351
	 */
352
	@Override
353
	public boolean onTouch(View v, MotionEvent event) {
354
		float x = (int) event.getRawX();
355
		float y = (int) event.getRawY();
356
		switch (event.getAction()) {
357
		case MotionEvent.ACTION_DOWN:
358
			mTouchStartX = event.getX();
359
			mTouchStartY = event.getY();
360
			mWmParams.alpha = 1f;
361
			mWindowManager.updateViewLayout(this, mWmParams);
362
			mDraging = false;
363
			break;
364
365
		case MotionEvent.ACTION_MOVE:
366
			float mMoveStartX = event.getX();
367
			float mMoveStartY = event.getY();
368
			if (Math.abs(mTouchStartX - mMoveStartX) > 2
369
			&& Math.abs(mTouchStartY - mMoveStartY) > 2) {
370
				mDraging = true;
371
				mWmParams.x = (int) (x - mTouchStartX);
372
				mWmParams.y = (int) (y - mTouchStartY);
373
				mWindowManager.updateViewLayout(this, mWmParams);
374
				if (mPathMenuLayout.isExpanded()) {
375
                    mHintView
376
                            .startAnimation(createHintSwitchAnimation(true));
377
                    mPathMenuLayout.switchState(true, position);
378
                }
379
				return false;
380
			}
381
			break;
382
383
		case MotionEvent.ACTION_UP:
384
		case MotionEvent.ACTION_CANCEL:
385
			int wmX = mWmParams.x;
386
			int wmY = mWmParams.y;
387
			if (wmX <= mScreenWidth / 8) // 左边 竖区域
388
			{
389
				if (wmY <= mScreenHeight / 8) {
390
					position = LEFT_TOP;// 左上
391
				} else if (wmY >= mScreenHeight / 8
392
						&& wmY <= mScreenHeight * 7 / 8) {
393
					position = LEFT_CENTER;// 左中
394
				} else if (wmY >= mScreenHeight * 7 / 8) {
395
					position = LEFT_BOTTOM;// 左下
396
				}
397
			} else if (wmX >= mScreenWidth / 8 && wmX <= mScreenWidth * 7 / 8)// 中间
398
																				// 竖区域
399
			{
400
				if (wmY <= mScreenHeight / 8) {
401
					position = CENTER_TOP;// 中上
402
				} else if (wmY >= mScreenHeight / 8
403
						&& wmY <= mScreenHeight * 7 / 8) {
404
					position = CENTER;// 中
405
				} else if (wmY >= mScreenHeight * 7 / 8) {
406
					position = CENTER_BOTTOM;// 中下
407
				}
408
			}
409
410
			else if (wmX >= mScreenWidth * 7 / 8)// 右边竖区域
411
			{
412
				if (wmY <= mScreenHeight / 8) {
413
					position = RIGHT_TOP;// 上右
414
				} else if (wmY >= mScreenHeight / 8
415
						&& wmY <= mScreenHeight * 7 / 8) {
416
					position = RIGHT_CENTER;// 中右
417
				} else if (wmY >= mScreenHeight * 7 / 8) {
418
					position = RIGHT_BOTTOM;// 下右
419
				}
420
			}
421
			refreshPathMenu(position);
422
423
			mWindowManager.updateViewLayout(this, mWmParams);
424
			mTouchStartX = mTouchStartY = 0;
425
			break;
426
		}
427
		return false;
428
	}
429
430
	/**
431
	 * 根据按钮位置改变子菜单方向
432
	 * 
433
	 * @param position
434
	 */
435
	private void refreshPathMenu(int position) {
436
		FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) mPathMenuLayout
437
				.getLayoutParams();
438
		FrameLayout.LayoutParams params1 = (FrameLayout.LayoutParams) controlLayout
439
				.getLayoutParams();
440
441
		switch (position) {
442
		case PathMenu.LEFT_TOP:// 左上
443
			params1.gravity = Gravity.LEFT | Gravity.TOP;
444
			params.gravity = Gravity.LEFT | Gravity.TOP;
445
			mPathMenuLayout.setArc(0, 90, position);
446
			break;
447
		case PathMenu.LEFT_CENTER:// 左中
448
			params1.gravity = Gravity.LEFT | Gravity.CENTER_VERTICAL;
449
			params.gravity = Gravity.LEFT | Gravity.CENTER_VERTICAL;
450
			mPathMenuLayout.setArc(270, 270 + 180, position);
451
			break;
452
		case PathMenu.LEFT_BOTTOM:// 左下
453
			params1.gravity = Gravity.LEFT | Gravity.BOTTOM;
454
			params.gravity = Gravity.LEFT | Gravity.BOTTOM;
455
			mPathMenuLayout.setArc(270, 360, position);
456
			break;
457
		case PathMenu.RIGHT_TOP:// 右上
458
			params1.gravity = Gravity.RIGHT | Gravity.TOP;
459
			params.gravity = Gravity.RIGHT | Gravity.TOP;
460
			mPathMenuLayout.setArc(90, 180, position);
461
			break;
462
		case PathMenu.RIGHT_CENTER:// 右中
463
			params1.gravity = Gravity.RIGHT | Gravity.CENTER_VERTICAL;
464
			params.gravity = Gravity.RIGHT | Gravity.CENTER_VERTICAL;
465
			mPathMenuLayout.setArc(90, 270, position);
466
			break;
467
		case PathMenu.RIGHT_BOTTOM:// 右下
468
			params1.gravity = Gravity.BOTTOM | Gravity.RIGHT;
469
			params.gravity = Gravity.BOTTOM | Gravity.RIGHT;
470
			mPathMenuLayout.setArc(180, 270, position);
471
			break;
472
473
		case PathMenu.CENTER_TOP:// 上中
474
			params1.gravity = Gravity.TOP | Gravity.CENTER_HORIZONTAL;
475
			params.gravity = Gravity.TOP | Gravity.CENTER_HORIZONTAL;
476
			mPathMenuLayout.setArc(0, 180, position);
477
			break;
478
		case PathMenu.CENTER_BOTTOM:// 下中
479
			params1.gravity = Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL;
480
			params.gravity = Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL;
481
			mPathMenuLayout.setArc(180, 360, position);
482
			break;
483
		case PathMenu.CENTER:
484
			params1.gravity = Gravity.CENTER;
485
			params.gravity = Gravity.CENTER;
486
			mPathMenuLayout.setArc(0, 360, position);
487
			break;
488
		}
489
		controlLayout.setLayoutParams(params1);
490
		mPathMenuLayout.setLayoutParams(params);
491
492
	}
493
494
	int statusBarHeight = 0;
495
496
	public int getStatusBarHeight() {
497
		if (statusBarHeight <= 0) {
498
			int resourceId = getResources().getIdentifier("status_bar_height",
499
					"dimen", "android");
500
			if (resourceId > 0) {
501
				statusBarHeight = getResources().getDimensionPixelSize(
502
						resourceId);
503
			}
504
		}
505
		return statusBarHeight;
506
	}
507
508
	public void hidePathMenu() {
509
		try {
510
			setVisibility(View.GONE);
511
		} catch (final IllegalArgumentException e) {
512
			Log.e("PathMenu", "hidePathMenu error!");
513
		}
514
	}
515
}

+ 0 - 39
ipu-pathmenu/src/com/ai/ipu/ipu_pathmenu/PathMenuActivity.java

@ -1,39 +0,0 @@
1
package com.ai.ipu.ipu_pathmenu;
2
3
import android.app.Activity;
4
import android.content.Intent;
5
import android.os.Bundle;
6
import android.view.View;
7
import android.view.View.OnClickListener;
8
import android.widget.Button;
9
10
public class PathMenuActivity extends Activity {
11
12
	@Override
13
	protected void onCreate(Bundle savedInstanceState) {
14
		super.onCreate(savedInstanceState);
15
		setContentView(R.layout.activity_float);
16
		Button btnOpen = (Button) findViewById(R.id.btnOpenFloat);
17
		Button btnClose = (Button) findViewById(R.id.btnCloseFloat);
18
19
		btnOpen.setOnClickListener(mClickListener);
20
		btnClose.setOnClickListener(mClickListener);
21
22
	}
23
24
	OnClickListener mClickListener = new OnClickListener() {
25
26
		@Override
27
		public void onClick(View v) {
28
			if (v.getId() == R.id.btnOpenFloat) {
29
				Intent intent = new Intent(PathMenuActivity.this,
30
						PathMenuService.class);
31
				startService(intent);
32
			} else if (v.getId() == R.id.btnCloseFloat) {
33
				Intent intent = new Intent(PathMenuActivity.this,
34
						PathMenuService.class);
35
				stopService(intent);
36
			}
37
		}
38
	};
39
}

+ 0 - 495
ipu-pathmenu/src/com/ai/ipu/ipu_pathmenu/PathMenuLayout.java

@ -1,495 +0,0 @@
1
package com.ai.ipu.ipu_pathmenu;
2
3
import android.content.Context;
4
import android.content.res.TypedArray;
5
import android.graphics.Rect;
6
import android.util.AttributeSet;
7
import android.view.View;
8
import android.view.ViewGroup;
9
import android.view.animation.AccelerateInterpolator;
10
import android.view.animation.Animation;
11
import android.view.animation.Animation.AnimationListener;
12
import android.view.animation.AnimationSet;
13
import android.view.animation.Interpolator;
14
import android.view.animation.LinearInterpolator;
15
import android.view.animation.OvershootInterpolator;
16
import android.view.animation.RotateAnimation;
17
18
/**
19
 * 子菜单项布局
20
 * 
21
 * @author 何凌波
22
 *
23
 */
24
public class PathMenuLayout extends ViewGroup {
25
	private int mChildSize; // 子菜单项大小相同
26
	private int mChildPadding = 5;
27
	private int mLayoutPadding = 10;
28
	public static final float DEFAULT_FROM_DEGREES = 270.0f;
29
	public static final float DEFAULT_TO_DEGREES = 360.0f;
30
	private float mFromDegrees = DEFAULT_FROM_DEGREES;
31
	private float mToDegrees = DEFAULT_TO_DEGREES;
32
	private static final int MIN_RADIUS = 100;
33
	private int mRadius;// 中心菜单圆点到子菜单中心的距离
34
	private boolean mExpanded = false;
35
	private int position = PathMenu.LEFT_TOP;
36
	private int centerX = 0;
37
	private int centerY = 0;
38
39
	public void computeCenterXY(int position) {
40
		switch (position) {
41
		case PathMenu.LEFT_TOP:// 左上
42
			centerX = getWidth() / 2 - getRadiusAndPadding();
43
			centerY = getHeight() / 2 - getRadiusAndPadding();
44
			break;
45
		case PathMenu.LEFT_CENTER:// 左中
46
			centerX = getWidth() / 2 - getRadiusAndPadding();
47
			centerY = getHeight() / 2;
48
			break;
49
		case PathMenu.LEFT_BOTTOM:// 左下
50
			centerX = getWidth() / 2 - getRadiusAndPadding();
51
			centerY = getHeight() / 2 + getRadiusAndPadding();
52
			break;
53
		case PathMenu.CENTER_TOP:// 上中
54
			centerX = getWidth() / 2;
55
			centerY = getHeight() / 2 - getRadiusAndPadding();
56
			break;
57
		case PathMenu.CENTER_BOTTOM:// 下中
58
			centerX = getWidth() / 2;
59
			centerY = getHeight() / 2 + getRadiusAndPadding();
60
			break;
61
		case PathMenu.RIGHT_TOP:// 右上
62
			centerX = getWidth() / 2 + getRadiusAndPadding();
63
			centerY = getHeight() / 2 - getRadiusAndPadding();
64
			break;
65
		case PathMenu.RIGHT_CENTER:// 右中
66
			centerX = getWidth() / 2 + getRadiusAndPadding();
67
			centerY = getHeight() / 2;
68
			break;
69
		case PathMenu.RIGHT_BOTTOM:// 右下
70
			centerX = getWidth() / 2 + getRadiusAndPadding();
71
			centerY = getHeight() / 2 + getRadiusAndPadding();
72
			break;
73
74
		case PathMenu.CENTER:
75
			centerX = getWidth() / 2;
76
			centerY = getHeight() / 2;
77
			break;
78
		}
79
	}
80
81
	private int getRadiusAndPadding() {
82
		return mRadius + (mChildPadding * 2);
83
	}
84
85
	public PathMenuLayout(Context context, AttributeSet attrs) {
86
		super(context, attrs);
87
		// 获取自定义属性,设定默认值
88
		if (attrs != null) {
89
			TypedArray a = getContext().obtainStyledAttributes(attrs,
90
					R.styleable.ArcLayout, 0, 0);
91
			mFromDegrees = a.getFloat(R.styleable.ArcLayout_fromDegrees,
92
					DEFAULT_FROM_DEGREES);
93
			mToDegrees = a.getFloat(R.styleable.ArcLayout_toDegrees,
94
					DEFAULT_TO_DEGREES);
95
			mChildSize = Math
96
					.max(a.getDimensionPixelSize(
97
							R.styleable.ArcLayout_childSize, 0), 0);
98
99
			a.recycle();
100
		}
101
	}
102
103
	/**
104
	 * 计算半径
105
	 * 
106
	 * @param arcDegrees
107
	 * @param childCount
108
	 * @param childSize
109
	 * @param childPadding
110
	 * @param minRadius
111
	 * @return
112
	 */
113
	private static int computeRadius(final float arcDegrees,
114
			final int childCount, final int childSize, final int childPadding,
115
			final int minRadius) {
116
		if (childCount < 2) {
117
			return minRadius;
118
		}
119
		final float perDegrees;
120
		if (arcDegrees < 360) {
121
			perDegrees = arcDegrees / (childCount - 1);
122
		} else {
123
			perDegrees = arcDegrees / (childCount);
124
		}
125
126
		final float perHalfDegrees = perDegrees / 2;
127
		final int perSize = childSize + childPadding;
128
129
		final int radius = (int) ((perSize / 2) / Math.sin(Math
130
				.toRadians(perHalfDegrees)));
131
132
		return Math.max(radius, minRadius);
133
	}
134
135
	/**
136
	 * 计算子菜单项的范围
137
	 * 
138
	 * @param centerX
139
	 * @param centerY
140
	 * @param radius
141
	 * @param degrees
142
	 * @param size
143
	 * @return
144
	 */
145
	private static Rect computeChildFrame(final int centerX, final int centerY,
146
			final int radius, final float degrees, final int size) {
147
		// 子菜单项中心点
148
		final double childCenterX = centerX + radius
149
				* Math.cos(Math.toRadians(degrees));
150
		final double childCenterY = centerY + radius
151
				* Math.sin(Math.toRadians(degrees));
152
		// 子菜单项的左上角,右上角,左下角,右下角
153
		return new Rect((int) (childCenterX - size / 2),
154
				(int) (childCenterY - size / 2),
155
				(int) (childCenterX + size / 2),
156
				(int) (childCenterY + size / 2));
157
	}
158
159
	/**
160
	 * 子菜单项大小
161
	 */
162
	@Override
163
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
164
		int radius = mRadius = computeRadius(
165
				Math.abs(mToDegrees - mFromDegrees), getChildCount(),
166
				mChildSize, mChildPadding, MIN_RADIUS);
167
168
		int size = radius * 2 + mChildSize + mChildPadding + mLayoutPadding * 2;
169
170
		setMeasuredDimension(size, size);
171
172
		final int count = getChildCount();
173
		for (int i = 0; i < count; i++) {
174
			getChildAt(i)
175
					.measure(
176
							MeasureSpec.makeMeasureSpec(mChildSize,
177
									MeasureSpec.EXACTLY),
178
							MeasureSpec.makeMeasureSpec(mChildSize,
179
									MeasureSpec.EXACTLY));
180
		}
181
	}
182
183
	/**
184
	 * 子菜单项位置
185
	 */
186
	@Override
187
	protected void onLayout(boolean changed, int l, int t, int r, int b) {
188
		computeCenterXY(position);
189
		// 当子菜单要收缩时radius=0,在ViewGroup坐标中心
190
		final int radius = mExpanded ? mRadius : 0;
191
		final float perDegrees;// 菜单项之间的角度
192
		final int childCount = getChildCount();
193
		if (mToDegrees - mFromDegrees >= 360) {
194
			perDegrees = (mToDegrees - mFromDegrees) / (childCount);
195
		} else {
196
			perDegrees = (mToDegrees - mFromDegrees) / (childCount - 1);
197
		}
198
199
		float degrees = mFromDegrees;
200
		for (int i = 0; i < childCount; i++) {
201
			Rect frame = computeChildFrame(centerX, centerY, radius, degrees,
202
					mChildSize);
203
			degrees += perDegrees;
204
			getChildAt(i).layout(frame.left, frame.top, frame.right,
205
					frame.bottom);
206
		}
207
	}
208
209
	/**
210
	 * 计算动画开始时的偏移量
211
	 * 
212
	 * @param childCount
213
	 * @param expanded
214
	 * @param index
215
	 * @param delayPercent
216
	 * @param duration
217
	 * @param interpolator
218
	 * @return
219
	 */
220
	private static long computeStartOffset(final int childCount,
221
			final boolean expanded, final int index, final float delayPercent,
222
			final long duration, Interpolator interpolator) {
223
		final float delay = delayPercent * duration;
224
		final long viewDelay = (long) (getTransformedIndex(expanded,
225
				childCount, index) * delay);
226
		final float totalDelay = delay * childCount;
227
228
		float normalizedDelay = viewDelay / totalDelay;
229
		normalizedDelay = interpolator.getInterpolation(normalizedDelay);
230
231
		return (long) (normalizedDelay * totalDelay);
232
	}
233
234
	/**
235
	 * 变换时的子菜单项索引
236
	 * 
237
	 * @param expanded
238
	 * @param count
239
	 * @param index
240
	 * @return
241
	 */
242
	private static int getTransformedIndex(final boolean expanded,
243
			final int count, final int index) {
244
		if (expanded) {
245
			return count - 1 - index;
246
		}
247
248
		return index;
249
	}
250
251
	/**
252
	 * 展开动画
253
	 * 
254
	 * @param fromXDelta
255
	 * @param toXDelta
256
	 * @param fromYDelta
257
	 * @param toYDelta
258
	 * @param startOffset
259
	 * @param duration
260
	 * @param interpolator
261
	 * @return
262
	 */
263
	private static Animation createExpandAnimation(float fromXDelta,
264
			float toXDelta, float fromYDelta, float toYDelta, long startOffset,
265
			long duration, Interpolator interpolator) {
266
		Animation animation = new RotateAndTranslateAnimation(0, toXDelta, 0,
267
				toYDelta, 0, 720);
268
		animation.setStartOffset(startOffset);
269
		animation.setDuration(duration);
270
		animation.setInterpolator(interpolator);
271
		animation.setFillAfter(true);
272
273
		return animation;
274
	}
275
276
	/**
277
	 * 收缩动画
278
	 * 
279
	 * @param fromXDelta
280
	 * @param toXDelta
281
	 * @param fromYDelta
282
	 * @param toYDelta
283
	 * @param startOffset
284
	 * @param duration
285
	 * @param interpolator
286
	 * @return
287
	 */
288
	private static Animation createShrinkAnimation(float fromXDelta,
289
			float toXDelta, float fromYDelta, float toYDelta, long startOffset,
290
			long duration, Interpolator interpolator) {
291
		AnimationSet animationSet = new AnimationSet(false);
292
		animationSet.setFillAfter(true);
293
		// 收缩过程中,child 逆时针自旋转360度
294
		final long preDuration = duration / 2;
295
		Animation rotateAnimation = new RotateAnimation(0, 360,
296
				Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,
297
				0.5f);
298
		rotateAnimation.setStartOffset(startOffset);
299
		rotateAnimation.setDuration(preDuration);
300
		rotateAnimation.setInterpolator(new LinearInterpolator());
301
		rotateAnimation.setFillAfter(true);
302
303
		animationSet.addAnimation(rotateAnimation);
304
		// 收缩过程中位移,并逆时针旋转360度
305
		Animation translateAnimation = new RotateAndTranslateAnimation(0,
306
				toXDelta, 0, toYDelta, 360, 720);
307
		translateAnimation.setStartOffset(startOffset + preDuration);
308
		translateAnimation.setDuration(duration - preDuration);
309
		translateAnimation.setInterpolator(interpolator);
310
		translateAnimation.setFillAfter(true);
311
312
		animationSet.addAnimation(translateAnimation);
313
314
		return animationSet;
315
	}
316
317
	/**
318
	 * 绑定子菜单项动画
319
	 * 
320
	 * @param child
321
	 * @param index
322
	 * @param duration
323
	 */
324
	private void bindChildAnimation(final View child, final int index,
325
			final long duration) {
326
		final boolean expanded = mExpanded;
327
		computeCenterXY(position);
328
		final int radius = expanded ? 0 : mRadius;
329
330
		final int childCount = getChildCount();
331
		final float perDegrees;
332
		if (mToDegrees - mFromDegrees >= 360) {
333
			perDegrees = (mToDegrees - mFromDegrees) / (childCount);
334
		} else {
335
			perDegrees = (mToDegrees - mFromDegrees) / (childCount - 1);
336
		}
337
		Rect frame = computeChildFrame(centerX, centerY, radius, mFromDegrees
338
				+ index * perDegrees, mChildSize);
339
340
		final int toXDelta = frame.left - child.getLeft();// 展开或收缩动画,child沿X轴位移距离
341
		final int toYDelta = frame.top - child.getTop();// 展开或收缩动画,child沿Y轴位移距离
342
343
		Interpolator interpolator = mExpanded ? new AccelerateInterpolator()
344
				: new OvershootInterpolator(1.5f);
345
		final long startOffset = computeStartOffset(childCount, mExpanded,
346
				index, 0.1f, duration, interpolator);
347
		// mExpanded为true,已经展开,收缩动画;为false,展开动画
348
		Animation animation = mExpanded ? createShrinkAnimation(0, toXDelta, 0,
349
				toYDelta, startOffset, duration, interpolator)
350
				: createExpandAnimation(0, toXDelta, 0, toYDelta, startOffset,
351
						duration, interpolator);
352
353
		final boolean isLast = getTransformedIndex(expanded, childCount, index) == childCount - 1;
354
		animation.setAnimationListener(new AnimationListener() {
355
356
			@Override
357
			public void onAnimationStart(Animation animation) {
358
359
			}
360
361
			@Override
362
			public void onAnimationRepeat(Animation animation) {
363
364
			}
365
366
			@Override
367
			public void onAnimationEnd(Animation animation) {
368
				if (isLast) {
369
					postDelayed(new Runnable() {
370
371
						@Override
372
						public void run() {
373
							onAllAnimationsEnd();
374
						}
375
					}, 0);
376
				}
377
			}
378
		});
379
380
		child.setAnimation(animation);
381
	}
382
383
	public boolean isExpanded() {
384
		return mExpanded;
385
	}
386
387
	/**
388
     * 设定弧度
389
     */
390
    public void setArc(float fromDegrees, float toDegrees, int position) {
391
        this.position = position;
392
        if (mFromDegrees == fromDegrees && mToDegrees == toDegrees) {
393
            return;
394
        }
395
396
        mFromDegrees = fromDegrees;
397
        mToDegrees = toDegrees;
398
        computeCenterXY(position);
399
        requestLayout();
400
    }
401
402
    /**
403
     * 设定弧度
404
     */
405
    public void setArc(float fromDegrees, float toDegrees) {
406
        if (mFromDegrees == fromDegrees && mToDegrees == toDegrees) {
407
            return;
408
        }
409
410
        mFromDegrees = fromDegrees;
411
        mToDegrees = toDegrees;
412
        computeCenterXY(position);
413
        requestLayout();
414
    }
415
416
417
	/**
418
	 * 设定子菜单项大小
419
	 * 
420
	 * @param size
421
	 */
422
	public void setChildSize(int size) {
423
		if (mChildSize == size || size < 0) {
424
			return;
425
		}
426
427
		mChildSize = size;
428
429
		requestLayout();
430
	}
431
432
	public int getChildSize() {
433
		return mChildSize;
434
	}
435
	
436
	public void setPosition(int position) {
437
        this.position = position;
438
        computeCenterXY(position);
439
        invalidate();
440
    }
441
	 /**
442
     * 切换中心按钮的展开缩小1
443
     * showAnimation一定要设置成true才有动画效果
444
     */
445
    public void switchState(final boolean showAnimation, int position) {
446
        this.position = position;
447
        if (showAnimation) {
448
            final int childCount = getChildCount();
449
            for (int i = 0; i < childCount; i++) {
450
                bindChildAnimation(getChildAt(i), i, 300);
451
            }
452
        }
453
454
        mExpanded = !mExpanded;
455
456
        if (!showAnimation) {
457
            requestLayout();
458
        }
459
460
        invalidate();
461
    }
462
	/**
463
	 * 切换中心按钮的展开缩小
464
	 * 
465
	 * @param showAnimation
466
	 */
467
	public void switchState(final boolean showAnimation) {
468
		if (showAnimation) {
469
			final int childCount = getChildCount();
470
			for (int i = 0; i < childCount; i++) {
471
				bindChildAnimation(getChildAt(i), i, 300);
472
			}
473
		}
474
475
		mExpanded = !mExpanded;
476
477
		if (!showAnimation) {
478
			requestLayout();
479
		}
480
481
		invalidate();
482
	}
483
484
	/**
485
	 * 结束所有动画
486
	 */
487
	private void onAllAnimationsEnd() {
488
		final int childCount = getChildCount();
489
		for (int i = 0; i < childCount; i++) {
490
			getChildAt(i).clearAnimation();
491
		}
492
493
		requestLayout();
494
	}
495
}

+ 0 - 94
ipu-pathmenu/src/com/ai/ipu/ipu_pathmenu/PathMenuService.java

@ -1,94 +0,0 @@
1
package com.ai.ipu.ipu_pathmenu;
2
3
4
import android.app.Service;
5
import android.content.Intent;
6
import android.os.IBinder;
7
import android.view.View;
8
import android.view.View.OnClickListener;
9
import android.widget.ImageView;
10
import android.widget.Toast;
11
12
public class PathMenuService extends Service {
13
	PathMenu pathMenu;
14
	private static int[] ITEM_DRAWABLES = {};
15
16
	@Override
17
	public IBinder onBind(Intent intent) {
18
		return null;
19
	}
20
21
	@Override
22
	public int onStartCommand(Intent intent, int flags, int startId) {
23
		ITEM_DRAWABLES = intent.getIntArrayExtra("icons");
24
		pathMenu = new PathMenu(getApplicationContext());
25
		initPathMenu(pathMenu, ITEM_DRAWABLES);// 初始化子菜单
26
		return super.onStartCommand(intent, flags, startId);
27
	}
28
29
	@Override
30
	public void onDestroy() {
31
		super.onDestroy();
32
		if (pathMenu != null) {
33
			pathMenu.hidePathMenu();
34
		}
35
	}
36
37
	/**
38
	 * 初始化子菜单图片、点击事件
39
	 * 
40
	 * @param menu
41
	 * @param itemDrawables
42
	 */
43
	private void initPathMenu(final PathMenu menu, final int[] itemDrawables) {
44
		final int itemCount = itemDrawables.length;
45
		for (int i = 0; i < itemCount; i++) {
46
			ImageView item = new ImageView(this);
47
			item.setImageResource(itemDrawables[i]);
48
			final int index = i;
49
			menu.addItem(item, new OnClickListener() {
50
51
				@Override
52
				public void onClick(View v) {
53
					switch (index) {
54
					case 0:
55
						Toast.makeText(PathMenuService.this, "关闭菜单",
56
								Toast.LENGTH_SHORT).show();
57
						stopSelf();// 关闭菜单
58
						break;
59
 
60
					case 1:
61
						Toast.makeText(PathMenuService.this, "第2个被点击",
62
								Toast.LENGTH_SHORT).show();
63
						break;
64
						
65
					case 2:
66
						Toast.makeText(PathMenuService.this, "第3个被点击",
67
								Toast.LENGTH_SHORT).show();
68
						break;
69
 
70
					case 3:
71
						Toast.makeText(PathMenuService.this, "第4个被点击",
72
								Toast.LENGTH_SHORT).show();
73
						break;
74
					case 4:
75
						Toast.makeText(PathMenuService.this, "第5个被点击",
76
								Toast.LENGTH_SHORT).show();
77
						break;
78
					case 5:
79
						Toast.makeText(PathMenuService.this, "第6个被点击",
80
								Toast.LENGTH_SHORT).show();
81
						break;
82
					case 6:
83
						Toast.makeText(PathMenuService.this, "第7个被点击",
84
								Toast.LENGTH_SHORT).show();
85
						break;
86
						
87
88
					}
89
				}
90
			});
91
		}
92
	}
93
	
94
}

+ 0 - 123
ipu-pathmenu/src/com/ai/ipu/ipu_pathmenu/RotateAndTranslateAnimation.java

@ -1,123 +0,0 @@
1
package com.ai.ipu.ipu_pathmenu;
2
3
import android.view.animation.Animation;
4
import android.view.animation.Transformation;
5
/**
6
 * 自定义动画类
7
 * 控制对象的位置,以对象的中心旋转
8
 * @author 何凌波
9
 *
10
 */
11
public class RotateAndTranslateAnimation extends Animation {
12
	private int mFromXType = ABSOLUTE;
13
14
	private int mToXType = ABSOLUTE;
15
16
	private int mFromYType = ABSOLUTE;
17
18
	private int mToYType = ABSOLUTE;
19
20
	private float mFromXValue = 0.0f;
21
22
	private float mToXValue = 0.0f;
23
24
	private float mFromYValue = 0.0f;
25
26
	private float mToYValue = 0.0f;
27
28
	private float mFromXDelta;
29
30
	private float mToXDelta;
31
32
	private float mFromYDelta;
33
34
	private float mToYDelta;
35
36
	private float mFromDegrees;
37
38
	private float mToDegrees;
39
40
	private int mPivotXType = ABSOLUTE;
41
42
	private int mPivotYType = ABSOLUTE;
43
44
	private float mPivotXValue = 0.0f;
45
46
	private float mPivotYValue = 0.0f;
47
48
	private float mPivotX;
49
50
	private float mPivotY;
51
52
	/**
53
	 * 位移动画的构造函数
54
	 * @param fromXDelta
55
	 *            动画开始时的X坐标
56
	 * @param toXDelta
57
	 *            动画结束时的X坐标
58
	 * @param fromYDelta
59
	 *            动画开始时的Y坐标
60
	 * @param toYDelta
61
	 *            动画结束时的Y坐标
62
	 * 
63
	 * @param fromDegrees
64
	 *            旋转开始时的角度
65
	 * @param toDegrees
66
	 *            旋转结束时的角度
67
	 */
68
	public RotateAndTranslateAnimation(float fromXDelta, float toXDelta,
69
			float fromYDelta, float toYDelta, float fromDegrees, float toDegrees) {
70
		mFromXValue = fromXDelta;
71
		mToXValue = toXDelta;
72
		mFromYValue = fromYDelta;
73
		mToYValue = toYDelta;
74
75
		mFromXType = ABSOLUTE;
76
		mToXType = ABSOLUTE;
77
		mFromYType = ABSOLUTE;
78
		mToYType = ABSOLUTE;
79
80
		mFromDegrees = fromDegrees;
81
		mToDegrees = toDegrees;
82
83
		mPivotXValue = 0.5f;
84
		mPivotXType = RELATIVE_TO_SELF;
85
		mPivotYValue = 0.5f;
86
		mPivotYType = RELATIVE_TO_SELF;
87
	}
88
89
	@Override
90
	protected void applyTransformation(float interpolatedTime, Transformation t) {
91
		final float degrees = mFromDegrees
92
				+ ((mToDegrees - mFromDegrees) * interpolatedTime);
93
		if (mPivotX == 0.0f && mPivotY == 0.0f) {
94
			t.getMatrix().setRotate(degrees);
95
		} else {
96
			t.getMatrix().setRotate(degrees, mPivotX, mPivotY);
97
		}
98
99
		float dx = mFromXDelta;
100
		float dy = mFromYDelta;
101
		if (mFromXDelta != mToXDelta) {
102
			dx = mFromXDelta + ((mToXDelta - mFromXDelta) * interpolatedTime);
103
		}
104
		if (mFromYDelta != mToYDelta) {
105
			dy = mFromYDelta + ((mToYDelta - mFromYDelta) * interpolatedTime);
106
		}
107
108
		t.getMatrix().postTranslate(dx, dy);
109
	}
110
111
	@Override
112
	public void initialize(int width, int height, int parentWidth,
113
			int parentHeight) {
114
		super.initialize(width, height, parentWidth, parentHeight);
115
		mFromXDelta = resolveSize(mFromXType, mFromXValue, width, parentWidth);
116
		mToXDelta = resolveSize(mToXType, mToXValue, width, parentWidth);
117
		mFromYDelta = resolveSize(mFromYType, mFromYValue, height, parentHeight);
118
		mToYDelta = resolveSize(mToYType, mToYValue, height, parentHeight);
119
120
		mPivotX = resolveSize(mPivotXType, mPivotXValue, width, parentWidth);
121
		mPivotY = resolveSize(mPivotYType, mPivotYValue, height, parentHeight);
122
	}
123
}

+ 0 - 50
ipu-pathmenu/src/com/ai/ipu/ipu_pathmenu/func/MobilePathMenu.java

@ -1,50 +0,0 @@
1
package com.ai.ipu.ipu_pathmenu.func;
2

3
import org.json.JSONArray;
4
import org.json.JSONObject;
5

6
import android.content.Intent;
7

8
import com.ai.ipu.ipu_pathmenu.PathMenuService;
9
import com.wade.mobile.frame.IWadeMobile;
10
import com.wade.mobile.frame.plugin.Plugin;
11

12
public class MobilePathMenu extends Plugin {
13
	public MobilePathMenu(IWadeMobile wademobile) {
14
		super(wademobile);
15
	}
16

17
	/**
18
	 * js传参数,调用原生方法
19
	 * 
20
	 * @param menuIcons
21
	 * @throws Exception
22
	 */
23
	public void openPathMenu(JSONArray param) throws Exception {
24
		JSONObject jsonObject = param.getJSONObject(0);
25
		JSONObject map = jsonObject.getJSONObject("map");
26
		int[] menuIcons = new int[map.length()];
27
		menuIcons[0] = map.getInt("composer_close");
28
		menuIcons[1] = map.getInt("composer_music");
29
		menuIcons[2] = map.getInt("composer_place");
30
		menuIcons[3] = map.getInt("composer_sleep");
31
		menuIcons[4] = map.getInt("composer_thought");
32
		menuIcons[5] = map.getInt("composer_with");
33
		openPathMenu(menuIcons);
34
	}
35

36
	public void openPathMenu(int[] menuIcons) {
37
		Intent intent = new Intent(context, PathMenuService.class);
38
		intent.putExtra("icons", menuIcons);
39
		context.startService(intent);
40
	}
41

42
	public void closePathMenu(JSONArray param) throws Exception {
43
		closePathMenu();
44
	}
45

46
	public void closePathMenu() {
47
		Intent intent = new Intent(context, PathMenuService.class);
48
		context.stopService(intent);
49
	}
50
}