Selaa lähdekoodia

更新PathMenu代码

leijie 8 vuotta sitten
vanhempi
commit
b5bb9380f6
1 muutettua tiedostoa jossa 247 lisäystä ja 48 poistoa
  1. 247 48
      wade-mobile-ui/src/com/wade/mobile/ui/comp/menu/PathMenu.java

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

@ -16,20 +16,19 @@ import android.view.animation.Animation.AnimationListener;
16 16
import android.widget.Button;
17 17
import android.widget.RelativeLayout;
18 18

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

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

521
		private Position(int position) {
522
			this.position = position;
523
		}
524

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