最近看到建设银行的主页面里面有一个带旋转效果的,心血来潮,正好公司最近活比较少,就花时间自己写了一个先上一下效果图
* 转盘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();
}
还有遇到最大的问题就是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的解决方法又重写了一份,第一份就不删了,可以参考作为错误的方法