浏览代码

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

chengwb3 8 年之前
父节点
当前提交
a39498f98f
共有 1 个文件被更改,包括 249 次插入48 次删除
  1. 249 48
      wade-mobile-ui/src/com/wade/mobile/ui/comp/menu/PathMenu.java

+ 249 - 48
wade-mobile-ui/src/com/wade/mobile/ui/comp/menu/PathMenu.java

3
import java.util.HashMap;
3
import java.util.HashMap;
4
import java.util.Map;
4
import java.util.Map;
5

5

6
import com.wade.mobile.ui.anim.AnimationTool;
7

6
import android.R.anim;
8
import android.R.anim;
7
import android.content.Context;
9
import android.content.Context;
8
import android.content.res.Resources;
10
import android.content.res.Resources;
16
import android.widget.Button;
18
import android.widget.Button;
17
import android.widget.RelativeLayout;
19
import android.widget.RelativeLayout;
18

20

19
import com.wade.mobile.ui.anim.AnimationTool;
20

21
public class PathMenu extends RelativeLayout{
21
public class PathMenu extends RelativeLayout{
22
	private Window window;
22
	private Window window;
23
	private int leftMargin, bottomMargin;						//左边距和底边距
23
	private int leftMargin, bottomMargin;						//左边距和底边距
24
	private int contentTopHeight;								//屏幕状态栏宽高
24
	private int contentTopHeight;								//屏幕状态栏宽高
25
	private int buttonRadius; 									//图片按钮
25
	private int buttonDiameter; 								//图片按钮
26
	private int radius; 										//扇形菜单半径
26
	private int radius; 										//扇形菜单半径
27
	private int originalRadius; 								//原始菜单半径
27
	private int timeSpent = 300; 								//最长动画耗时
28
	private int timeSpent = 300; 								//最长动画耗时
28
	private int alpha = 127;									//透明度 0-255
29
	private int alpha = 127;									//透明度 0-255
29
	private double circle = Math.PI;							//扇形菜单占据一圈的比例,0~1 		
30
	private double circle = Math.PI;							//扇形菜单占据一圈的比例,0~1 		
30
	/*
31
	private int intervalTimeSpent;                             	//菜单按钮之间的时间间隔
32
	*/
31
	
32
	//private int intervalTimeSpent;                            //菜单按钮之间的时间间隔
33
	
33
	private Button[] buttons;									//Path菜单按钮引用
34
	private Button[] buttons;									//Path菜单按钮引用
34
	private int[] drawables;									//菜单子按钮的图片
35
	private int[] drawables;									//菜单子按钮的图片
35
	private int menuDrawable;									//菜单按钮的图片
36
	private int menuDrawable;									//菜单按钮的图片
46
	
47
	
47
	private Map<String,Animation> animCache;					//动画缓存
48
	private Map<String,Animation> animCache;					//动画缓存
48
	
49
	
50
	private Position position;										//pathmenu位置
51
	private boolean isLeft,isRight,isUp,isBottom;				//是否停边
52
	
53
	int screenWidth,screenHeight;
54
	
55
	private long touchStartTime;		
56
	
49
	/**click事件*/
57
	/**click事件*/
50
	View.OnClickListener clickListener=new View.OnClickListener(){
58
	View.OnClickListener clickListener=new View.OnClickListener(){
51
		public void onClick(View v) {
59
		public void onClick(View v) {
72
			int btnHeight = menuBtn.getHeight();
80
			int btnHeight = menuBtn.getHeight();
73
			switch (event.getAction()) {
81
			switch (event.getAction()) {
74
			case MotionEvent.ACTION_DOWN:
82
			case MotionEvent.ACTION_DOWN:
83
				touchStartTime = System.currentTimeMillis();
75
				focusView(menuBtn);//获取焦点
84
				focusView(menuBtn);//获取焦点
76
				menuBtnX = menuBtn.getLeft();
85
				menuBtnX = menuBtn.getLeft();
77
				menuBtnY = menuBtn.getBottom();
86
				menuBtnY = menuBtn.getBottom();
78
				break;
87
				break;
79
			case MotionEvent.ACTION_MOVE:
88
			case MotionEvent.ACTION_MOVE:
80
				if(isCanDrag){
81
					int x_move = (int) event.getRawX();
82
					int y_move = (int) event.getRawY();
83
					
84
					/*滑动到一定程度时候才出发拖拽*/
85
					if(!isDrag&&((Math.abs(menuBtnX+btnWidth/2-x_move)>buttonRadius)
86
							||(Math.abs(menuBtnY+contentTopHeight-btnHeight/2-y_move)>buttonRadius))){
87
						isDrag = true;
88
					}
89
					
90
					if(isDrag){
91
						int top = y_move - btnHeight / 2 - contentTopHeight;
92
						int bottom = y_move + btnHeight / 2 - contentTopHeight;
93
						/*防止越界top,标题栏+状态栏*/
94
						if(y_move<contentTopHeight){
95
							top = -btnHeight / 2;
96
							bottom = btnHeight / 2;
89
				if(500 <= System.currentTimeMillis() - touchStartTime){ //当执行触摸时间大于0.5秒时,才执行移动;避免因屏幕敏感导致点击变成滑动事件
90
					if(isCanDrag){
91
						int x_move = (int) event.getRawX();
92
						int y_move = (int) event.getRawY();
93
						/*滑动到一定程度时候才出发拖拽*/
94
						if(!isDrag&&((Math.abs(menuBtnX+btnWidth/2-x_move)>(buttonDiameter/8))
95
								||(Math.abs(menuBtnY+contentTopHeight-btnHeight/2-y_move)>(buttonDiameter/8)))){
96
							isDrag = true;
97
						}
98
						
99
						if(isDrag){
100
							int top = y_move - btnHeight / 2 - contentTopHeight;
101
							int bottom = y_move + btnHeight / 2 - contentTopHeight;
102
							int left = x_move -  btnWidth / 2;
103
							int right = x_move + btnWidth / 2;
104
							/*防止越界top,标题栏+状态栏*/
105
							if(y_move<contentTopHeight + btnHeight/2){
106
								top = 0;
107
								bottom = btnHeight;
108
							}
109
							/*防止越界bottom*/
110
							if(screenHeight - y_move - btnHeight/2<= 0){
111
								top = screenHeight - contentTopHeight - btnHeight;
112
								bottom = screenHeight - contentTopHeight ;
113
							}
114
							if(x_move <= btnWidth/2){
115
								left = 0;
116
								right = btnWidth;
117
							}
118
							if(x_move >= screenWidth - btnWidth/2){
119
								left = screenWidth - btnWidth;
120
								right = screenWidth;
121
							}
122
							menuBtn.layout(left , top, right, bottom);
123
							menuBtn.postInvalidate();
97
						}
124
						}
98
						menuBtn.layout(x_move - btnWidth / 2, top, x_move + btnWidth / 2, bottom);
99
						menuBtn.postInvalidate();
100
					}
125
					}
101
				}
126
				}
102
				break;
127
				break;
119
					isDrag = false;
144
					isDrag = false;
120
				}else{
145
				}else{
121
					if(isOpen()){
146
					if(isOpen()){
122
						PathMenu.this.shutMenu();
147
						PathMenu.this.shutMenu(position);
123
					}else{
148
					}else{
124
						PathMenu.this.openMenu();
149
						//判断靠边类型
150
						int x_up = menuBtn.getLeft();
151
						int y_up = menuBtn.getBottom();
152
						
153
						 /*根据离屏幕边框的距离判断菜单展开形状*/
154
						if (x_up + buttonDiameter/2 < originalRadius) {//x=0是指圆形按钮的最左边,而否中心
155
							isLeft = true;
156
						} else {
157
							isLeft = false;
158
						}
159
						if (screenWidth - x_up - buttonDiameter/2 < originalRadius) {
160
							isRight = true;
161
						} else {
162
							isRight = false;
163
						}
164
						if (y_up - buttonDiameter/2 - contentTopHeight< originalRadius) {
165
							isUp = true;
166
						} else {
167
							isUp = false;
168
						}
169
						if (screenHeight - y_up - buttonDiameter/2 < originalRadius) {
170
							isBottom = true;
171
						} else {
172
							isBottom = false;
173
						}
174
						position = getPosition(isLeft, isRight, isUp, isBottom);
175
						PathMenu.this.openMenu(position);
125
					}
176
					}
126
				}
177
				}
127
				break;
178
				break;
148
	}
199
	}
149
	
200
	
150
	/*********************设置属性 start*************************/
201
	/*********************设置属性 start*************************/
151
	public PathMenu setButtonRadius(int buttonRadius){
152
		if(this.buttonRadius<=0){
153
			this.buttonRadius = buttonRadius;
202
	public PathMenu setButtonDiameter(int buttonDiameter){
203
		if(this.buttonDiameter<=0){
204
			this.buttonDiameter = buttonDiameter;
154
		}
205
		}
155
		return this;
206
		return this;
156
	}
207
	}
158
	public PathMenu setRadius(int radius){
209
	public PathMenu setRadius(int radius){
159
		if(this.radius<=0){
210
		if(this.radius<=0){
160
			this.radius = radius;
211
			this.radius = radius;
212
			this.originalRadius = radius;
161
		}
213
		}
162
		return this;
214
		return this;
163
	}
215
	}
178
		if(circle>1)
230
		if(circle>1)
179
			circle = 1;
231
			circle = 1;
180
		this.circle = 2*Math.PI*circle;
232
		this.circle = 2*Math.PI*circle;
181
		this.angle=(float)this.circle/(buttons.length-1);
233
		if(circle == 1){			
234
			this.angle=(float)this.circle/(buttons.length);
235
		}else {
236
			this.angle=(float)this.circle/(buttons.length - 1);
237
		}
182
		return this;
238
		return this;
183
	}
239
	}
184
	
240
	
210
	    menuBtn.setBackgroundDrawable(resources.getDrawable(menuDrawable));  
266
	    menuBtn.setBackgroundDrawable(resources.getDrawable(menuDrawable));  
211
	    this.addView(menuBtn);
267
	    this.addView(menuBtn);
212
	    
268
	    
213
	    angle=(float)circle/(buttons.length-1);
269
//	    angle=(float)circle/(buttons.length-1);
214
	    
270
	    
215
	    setVisibility(View.INVISIBLE);
271
	    setVisibility(View.INVISIBLE);
216
	}
272
	}
225
		/*初始化默认值*/
281
		/*初始化默认值*/
226
		DisplayMetrics dm = new DisplayMetrics();                   		
282
		DisplayMetrics dm = new DisplayMetrics();                   		
227
        window.getWindowManager().getDefaultDisplay().getMetrics(dm);       //取得窗口属性  
283
        window.getWindowManager().getDefaultDisplay().getMetrics(dm);       //取得窗口属性  
228
        int screenWidth = (int)dm.widthPixels;                        		//窗口的宽度   
284
        screenWidth = (int)dm.widthPixels;                        		//窗口的宽度   
285
        screenHeight = (int)dm.heightPixels;
229
		
286
		
230
        /*计算标题栏和状态栏的高度*/
287
        /*计算标题栏和状态栏的高度*/
231
        if(this.contentTopHeight<=0){
288
        if(this.contentTopHeight<=0){
232
        	this.contentTopHeight = window.findViewById(Window.ID_ANDROID_CONTENT).getTop();
289
        	this.contentTopHeight = window.findViewById(Window.ID_ANDROID_CONTENT).getTop();
233
        }
290
        }
234
        
291
        
235
    	setButtonRadius(screenWidth / 8);
236
    	setRadius(this.buttonRadius * 2);
292
        setButtonDiameter(screenWidth / 8);
293
    	setRadius(this.buttonDiameter * 2);
237
		
294
		
238
		leftMargin = xposition - buttonRadius/2;
239
		bottomMargin = yposition - buttonRadius - contentTopHeight;
295
		leftMargin = xposition - buttonDiameter/2;
296
		bottomMargin = yposition - buttonDiameter - contentTopHeight;
240
		
297
		
241
		/*触发点越界时候的情况*/
298
		/*触发点越界时候的情况*/
242
		/*if(leftMargin + radius + buttonWidth > spacingWidth){
299
		/*if(leftMargin + radius + buttonWidth > spacingWidth){
249
		/*设置所有按钮的位置*/
306
		/*设置所有按钮的位置*/
250
		RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
307
		RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
251
				ViewGroup.LayoutParams.WRAP_CONTENT);
308
				ViewGroup.LayoutParams.WRAP_CONTENT);
252
		params.height = buttonRadius;
253
		params.width =  buttonRadius;											
309
		params.height = buttonDiameter;
310
		params.width =  buttonDiameter;											
254
		params.setMargins(leftMargin, bottomMargin, 0, 0);
311
		params.setMargins(leftMargin, bottomMargin, 0, 0);
255
		
312
		
256
		for (int i = 0; i < buttons.length; i++) {
313
		for (int i = 0; i < buttons.length; i++) {
288
		isOpen = true;
345
		isOpen = true;
289
	}
346
	}
290
	
347
	
291
	public void openMenu() {
348
	public void openMenu(Position position) {
349
//		if(position != 0 && position % 2 == 0){//当position为扇形,打开时初始半径变大1.5倍;
350
//			radius *= 1.5;
351
//		}
352
		
292
		int toX,toY;
353
		int toX,toY;
293
		for(int i=0;i<buttons.length;i++){
354
		for(int i=0;i<buttons.length;i++){
294
			buttons[i].setVisibility(View.VISIBLE);
355
			buttons[i].setVisibility(View.VISIBLE);
295
			
356
			
296
			toX=(int)(radius*Math.sin(i*angle-Math.PI/2));
297
			toY=(int)(radius*Math.cos(i*angle-Math.PI/2));
357
//			toX=(int)(radius*Math.sin(i*angle));
358
//			toY=(int)(radius*Math.cos(i*angle));
359
			toX = computOffset(position, i)[0];
360
			toY = computOffset(position, i)[1];
298
			
361
			
299
			Animation animation = animOpen(toX, -toY, timeSpent/*+i*intervalTimeSpent*/);
362
			Animation animation = animOpen(toX, -toY, timeSpent/*+i*intervalTimeSpent*/);
300
			/*animation.setFillAfter(true);*/ //达不到既定的效果
363
			/*animation.setFillAfter(true);*/ //达不到既定的效果
309
	/**
372
	/**
310
	 * 关闭菜单
373
	 * 关闭菜单
311
	 */
374
	 */
312
	public void shutMenu(){
375
	/**
376
	 * @param position
377
	 */
378
	/**
379
	 * @param position
380
	 */
381
	public void shutMenu(Position position){
313
		float toX, toY;
382
		float toX, toY;
314
		for (int i = 0; i < buttons.length; i++) {
383
		for (int i = 0; i < buttons.length; i++) {
315
			toX=(float)(radius*Math.sin(i*angle-Math.PI/2));
316
			toY=(float)(radius*Math.cos(i*angle-Math.PI/2));
384
//			toX=(float)(radius*Math.sin(i*angle - Math.PI));
385
//			toY=(float)(radius*Math.cos(i*angle - Math.PI));
386
			
387
			toX = computOffset(position, i)[0];
388
			toY = computOffset(position, i)[1];
389
			
317
			buttons[i].startAnimation(animShut(buttons[i], -toX, toY, timeSpent));//点击按钮变大
390
			buttons[i].startAnimation(animShut(buttons[i], -toX, toY, timeSpent));//点击按钮变大
318
		}
391
		}
319
		isOpen = false;
392
		isOpen = false;
320
		isCanDrag = true;
393
		isCanDrag = true;
394
		
395
//		if(position != 0 && position % 2 == 0){//当position为扇形,关闭时恢复初始半径;
396
//			radius /= 1.5;
397
//		}
321
	}
398
	}
322
	
399
	
323
	/************************动画效果实现start***************************/
400
	/************************动画效果实现start***************************/
363
	public void reset(){
440
	public void reset(){
364
		/*解决Home出去时的BUG*/
441
		/*解决Home出去时的BUG*/
365
		if(this.isOpen){
442
		if(this.isOpen){
366
			shutMenu();
443
			shutMenu(position);
367
		}
444
		}
368
		this.isOpen = false;
445
		this.isOpen = false;
369
		this.isCanDrag = true;
446
		this.isCanDrag = true;
402
			button.clearAnimation();
479
			button.clearAnimation();
403
			
480
			
404
			/*1.设置button,解决跨线程调用,Handle的实现在ViewRoot中,触发invalidate()*/
481
			/*1.设置button,解决跨线程调用,Handle的实现在ViewRoot中,触发invalidate()*/
405
			button.layout(left, bottom,left+buttonRadius, bottom+buttonRadius);
482
			button.layout(left, bottom,left+buttonDiameter, bottom+buttonDiameter);
406
			button.postInvalidate();
483
			button.postInvalidate();
407
			/*2.最原始的方式设置button*/
484
			/*2.最原始的方式设置button*/
408
			/*RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
485
			/*RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
428
	public void setOnButtonClickListener(OnButtonClickListener onButtonClickListener){
505
	public void setOnButtonClickListener(OnButtonClickListener onButtonClickListener){
429
		this.onButtonClickListener = onButtonClickListener;
506
		this.onButtonClickListener = onButtonClickListener;
430
	}
507
	}
431
}
508
	
509
	/********展开形状判定**********/
510
	public static enum Position {
511
		CENTER(0),				//中心正圆
512
	    TOP_CENTER(1),			//上中半圆
513
	    TOP_RIGHT(2),			//上右扇形
514
	    RIGHT_CENTER(3),		//右中半圆
515
	    BOTTOM_RIGHT(4),		//底右扇形
516
	    BOTTOM_CENTER(5),		//底中半圆
517
	    BOTTOM_LEFT(6),			//底左扇形
518
	    LEFT_CENTER(7),			//左中半圆
519
	    TOP_LEFT(8);			//上左扇形
520
	    
521
		private int position;
522

523
		private Position(int position) {
524
			this.position = position;
525
		}
526

527
		public int getPosition() {
528
			return this.position;
529
		}
530
	}
531
	
532
	/**
533
	 * 通过距离动态判断停靠位置
534
	 * @param isLeft
535
	 * @param isRight
536
	 * @param isUp
537
	 * @param isBottom
538
	 * @return
539
	 */
540
	private Position getPosition(boolean isLeft,boolean isRight,boolean isUp,boolean isBottom){
541
		if (isBottom) {
542
			if(isRight){
543
				return Position.BOTTOM_RIGHT;
544
			}else if (isLeft) {
545
				return Position.BOTTOM_LEFT;
546
			}else{
547
				return Position.BOTTOM_CENTER;
548
			}
549
		}else if (isUp) {
550
			if(isRight){
551
				return Position.TOP_RIGHT;
552
			}else if (isLeft) {
553
				return Position.TOP_LEFT;
554
			}else{
555
				return Position.TOP_CENTER;
556
			}
557
		}else if (isRight) {
558
			return Position.RIGHT_CENTER;
559
		}else if (isLeft) {
560
			return Position.LEFT_CENTER;
561
		}else{
562
			return Position.CENTER;
563
		}
564
	}
565
	/**
566
	 * 偏移量计算
567
	 */
568
	private int[] computOffset(Position position,int i){
569
		int toX = 0,toY =0 ;
570
		radius = buttonDiameter * 2;
571
		if(position.getPosition() != 0 && position.getPosition() % 2 == 0){//当position为扇形,打开时初始半径变大1.5倍;
572
			radius *= 1.5;
573
		}
574
		switch (position) {
575
		case CENTER:
576
			setCircle(1);
577
			toX =(int)(radius*Math.sin(i*angle));
578
			toY =(int)(radius*Math.cos(i*angle));
579
			break;
580
		case TOP_CENTER:
581
			setCircle(0.5f);
582
			toX = (int)(radius*Math.sin(i*angle + Math.PI/2));
583
			toY = (int)(radius*Math.cos(i*angle + Math.PI/2));
584
			break;
585
		case TOP_RIGHT:
586
			setCircle(0.25f);
587
			toX = (int)(radius*Math.sin(i*angle + Math.PI));
588
			toY = (int)(radius*Math.cos(i*angle + Math.PI));
589
			break;
590
		case RIGHT_CENTER:
591
			setCircle(0.5f);
592
			toX = (int)(radius*Math.sin(i*angle + Math.PI));
593
			toY = (int)(radius*Math.cos(i*angle + Math.PI));
594
			break;
595
		case BOTTOM_RIGHT:
596
			setCircle(0.25f);
597
			toX = (int)(radius*Math.sin(i*angle - Math.PI/2));
598
			toY = (int)(radius*Math.cos(i*angle - Math.PI/2));
599
			break;
600
		case BOTTOM_CENTER:
601
			setCircle(0.5f);
602
			toX = (int)(radius*Math.sin(i*angle - Math.PI/2));
603
			toY = (int)(radius*Math.cos(i*angle - Math.PI/2));
604
			break;
605
		case BOTTOM_LEFT:
606
			setCircle(0.25f);
607
			toX = (int)(radius*Math.sin(i*angle));
608
			toY = (int)(radius*Math.cos(i*angle));
609
			break;
610
		case LEFT_CENTER:
611
			setCircle(0.5f);
612
			toX = (int)(radius*Math.sin(i*angle));
613
			toY = (int)(radius*Math.cos(i*angle));
614
			break;
615
		case TOP_LEFT:
616
			setCircle(0.25f);
617
			toX = (int)(radius*Math.sin(i*angle + Math.PI/2));
618
			toY = (int)(radius*Math.cos(i*angle + Math.PI/2));
619
			break;
620
		default:
621
			break;
622
		}
623
		int [] xy = {toX,toY};
624
		return xy;
625
	}
626
	
627
	public PathMenu setPosition(Position position){
628
		this.position = position;
629
		return this;
630
	}
631
	
632
}