最近看到建设银行的主页面里面有一个带旋转效果的,心血来潮,正好公司最近活比较少,就花时间自己写了一个先上一下效果图
* 转盘viewgroup,将会已转盘的形式排列所有子view,view之间间距一样,所以不要添加过多的view
* 支持长按删除
* 支持复位播放音效
图有点大,也不知道如何缩小,大家凑合看看
代码其实也比较简单,我就贴出来比较重要的代码让大家看看
首先当然是手势的处理,我是把一个圆圈用一个“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(); }
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的解决方法又重写了一份,第一份就不删了,可以参考作为错误的方法
第二版本源码点我下载