android一个转盘效果的容器viewgroup

最近看到建设银行的主页面里面有一个带旋转效果的,心血来潮,正好公司最近活比较少,就花时间自己写了一个先上一下效果图


 * 转盘viewgroup,将会已转盘的形式排列所有子view,view之间间距一样,所以不要添加过多的view
 * 支持长按删除
 * 支持复位播放音效


android一个转盘效果的容器viewgroup_第1张图片


图有点大,也不知道如何缩小,大家凑合看看

代码其实也比较简单,我就贴出来比较重要的代码让大家看看

首先当然是手势的处理,我是把一个圆圈用一个“X”型,给他分成四部分

	private int checkArea(float x, float y){
		int locationInWindow[] = new int[2];
		getLocationInWindow(locationInWindow);
		int parentX = locationInWindow[0] + getWidth()/2;
		int parentY = locationInWindow[1] + getHeight()/2;
		double distance = Math.sqrt((parentX - x)*(parentX - x) + (parentY - y)*(parentY - y));//两个点之间的距离
		double disY = Math.abs(y - parentY);
		double radian = Math.asin(disY/distance);
		double angle = (radian / Math.PI) * 180;
		if(y <= parentY && x <= parentX){// 1,4象限
			if(angle < 45)
				return 4;
			else
				return 1;
		}else if(y <= parentY && x >= parentX){ //1,2象限
			if(angle <=90 && angle >=45)
				return 1;
			else
				return 2;	
		}else if(y >= parentY && x >= parentX){//2,3象限
			if(angle <= 45)
				return 2;
			else
				return 3;
		}else{// 3,4象限
			if(angle < 45)
				return 4;
			else
				return 3;
		}
	}
不同的象限所处理的手势也不一样,为了简单方便,1.3象限只处理x轴的滑动,2,4象限只处理y轴的滑动

case MotionEvent.ACTION_MOVE:
			area = checkArea(event.getRawX(), event.getRawY());
			float moveY = event.getRawY() - lastY;
			float moveX = event.getRawX() - lastX;
			switch (area) {
			case 1:
				turnClockwise(moveX);
				speed = moveX;
				break;
			case 2:
				turnClockwise(moveY);
				speed = moveY;
				break;
			case 3:
				turnClockwise(-moveX);
				speed = -moveX;
				break;
			case 4:
				turnClockwise(-moveY);
				speed = -moveY;
				break;
			}
			lastX = event.getRawX();
			lastY = event.getRawY();
			break;
旋转函数
	private void turnClockwise(float move){
		float angle = move / 5;
		for(int i=0 ; i<location.size() ; i++){
			location.get(i).setNumber((location.get(i).getNumber() + angle)%360);
			if(location.get(i).getNumber() >= -10 && location.get(i).getNumber() <= 10 ){//需要一个范围
				if(location.get(i).isFlag()){
					sound.onPlaySound();
					location.get(i).setFlag(false); //用于表示该图标已经播放完声音
				}
			}
			else{
				location.get(i).setFlag(true);
			}
		}
		requestLayout();//重新计算每个子view的位置
//		invalidate();
	}

还有遇到最大的问题就是touchevent的冲突,由于父控件处理了所有的touchevent,所以子控件没收到touchevent,于是就用了SimpleOnGestureListener来处理,再onTouchEvent函数里面将每一个touchevent都传到SimpleOnGestureListener里面,接着重写onSingleTapUp函数来处理单击事件即可,虽然这样也能够处理了,但是感觉效果还是不太好,如果来处理子空间的滑动动作呢?

private class MyGestureDetectorListener extends SimpleOnGestureListener{

		/**
		 * down事件
		 */
		@Override
		public boolean onDown(MotionEvent arg0) {
			return false;
		}

		/**
		 * 滑动手势事件;Touch了滑动一点距离后,在ACTION_UP时才会触发       
			参数:e1 第1个ACTION_DOWN MotionEvent 并且只有一个;
			e2 最后一个ACTION_MOVE MotionEvent ;velocityX X轴上的移动速度,像素/秒 ;
			velocityY Y轴上的移动速度,像素/秒.触发条件:X轴的坐标位移大于FLING_MIN_DISTANCE,
			且移动速度大于FLING_MIN_VELOCITY个像素/秒
		 */
		@Override
		public boolean onFling(MotionEvent arg0, MotionEvent arg1, float arg2,
				float arg3) {
			return false;
		}

		/**
		 * 长按事件;Touch了不移动一直Touch down时触发 
		 */
		@Override
		public void onLongPress(MotionEvent arg0) {
			viewIsBeingLongClick = getChildAt(checkClickChild(arg0.getX(), arg0.getY()));
//			initPopUpMenu(); ---1
//			showContextMenuForChild(viewIsBeingLongClick); ---2
//			menu.show();
			initPopUpWindow();
			
			window.showAsDropDown(viewIsBeingLongClick);
		}

		/**
		 * 拖动事件。无论是用手拖动view,或者是以抛的动作滚动,都会多次触发,这个方法在ACTION_MOVE动作发生时就会触发
        抛:手指触动屏幕后,稍微滑动后立即松开
		onDown-----》onScroll----》onScroll----》onScroll----》………----->onFling 
		拖动
		onDown------》onScroll----》onScroll------》onFiling
		 */
		@Override
		public boolean onScroll(MotionEvent arg0, MotionEvent arg1, float arg2,
				float arg3) {
			return false;
		}

		/**
		 * down事件发生而move或则up还没发生前触发该   
			事件;Touch了还没有滑动时触发(与onDown,onLongPress)比较onDown只要Touch down一定立刻触发。
			而Touchdown后过一会没有滑动先触发onShowPress再是onLongPress。所以Touchdown后一直不滑动
			按照onDown->onShowPress->onLongPress这个顺序触发。
		 */
		@Override
		public void onShowPress(MotionEvent arg0) {
			
		}

		/**
		 * 一次点击up事件;在touch down后又没有滑动
			(onScroll),又没有长按(onLongPress),然后Touchup时触发。
			 点击一下非常快的(不滑动)Touchup:
			onDown->onSingleTapUp->onSingleTapConfirmed 
			          点击一下稍微慢点的(不滑动)Touchup:
			onDown->onShowPress->onSingleTapUp->onSingleTapConfirmed
		 */
		@Override
		public boolean onSingleTapUp(MotionEvent arg0) {
			if(listener != null){
				int i = checkClickChild(arg0.getX(), arg0.getY());
				if( i != -1)
					listener.onClick((String) getChildAt(i).getTag());
			}
			return false;
		}
	}
点我下载

----------------------------------------------------------------------------------------------------------------------------------------------------------------------

最近又重写了一下,发现oninterceptouchevent函数直接返回true这种做法非常不合理,甚至说是错误的,因为这样一定会造成子控件接收不到touchevent,所以参照scrollview的解决方法又重写了一份,第一份就不删了,可以参考作为错误的方法

第二版本源码点我下载


你可能感兴趣的:(android)