public interface ChildsMenu { public Point DEFAULT_POSITION = new Point(0, 0); public void showChilds(View[] view); public void notifyLocationSetChanged(); }ChildsMenuLayout.java:
public class ChildsMenuLayout extends RelativeLayout implements ChildsMenu { public double radius = 140d; private Point position = DEFAULT_POSITION; private List<PointF> points; private Context mContext; private View[] views; private LOCATION location; private boolean isShow = false; public ChildsMenuLayout(Context context) { super(context); // TODO Auto-generated constructor stub mContext = context; setWillNotDraw(false); } public ChildsMenuLayout(Context context, AttributeSet attrs) { super(context, attrs); // TODO Auto-generated constructor stub mContext = context; setWillNotDraw(false); } public ChildsMenuLayout(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); // TODO Auto-generated constructor stub mContext = context; setWillNotDraw(false); } @Override public void showChilds(View[] views) { // TODO Auto-generated method stub isShow = true; this.views = views; points = getDataPoints(views); this.invalidate(); } public void hideChilds() { isShow = false; this.invalidate(); } private List<PointF> getDataPoints(View[] views) { if (views == null) { isShow = false; return null; } Location locationOnScreen = new Location(mContext , this); location = locationOnScreen.getLocation(); List<PointF> points = new ArrayList<PointF>(); int count = views.length; double unitRadian = 0; double startRadian = 0; double endRadian = 0; final int Clockwise = 1;//顺时针 final int Eastern = -1;//逆时针 int direction = Clockwise; double temp; switch (location) { case BOUNDARY_BOTTOM: temp =Math.PI/2 - Math.asin((locationOnScreen.bottom + radius)/radius); unitRadian = 2*(Math.PI -temp)/ (count - 1); direction = Clockwise; startRadian = -Math.PI*3/2+temp; break; case BOUNDARY_LEFT: temp =Math.PI/2 - Math.asin((locationOnScreen.left + radius)/radius); unitRadian = 2*(Math.PI - temp) / (count - 1); direction = Clockwise; startRadian = -Math.PI + temp; break; case BOUNDARY_RIGHT: temp =Math.PI/2 - Math.asin((locationOnScreen.right + radius)/radius); unitRadian = 2*(Math.PI - temp) / (count - 1); direction = Eastern; startRadian = - temp; break; case BOUNDARY_TOP: temp =Math.PI/2 - Math.asin((locationOnScreen.top + radius)/radius); unitRadian = 2*(Math.PI -temp) / (count - 1); direction = Eastern; startRadian = -Math.PI/2 - temp; break; case CENTER: unitRadian = Math.PI * 2 / count; direction = Clockwise; startRadian = -Math.PI; break; case CORNER_LEFT_BOTTOM: startRadian = Math.asin((radius+locationOnScreen.left)/radius); endRadian = Math.asin((radius+locationOnScreen.bottom)/radius); unitRadian = (Math.PI / 2+startRadian+endRadian) / (count - 1); direction = Clockwise; startRadian = -Math.PI / 2 -startRadian; break; case CORNER_LEFT_TOP: startRadian = Math.asin((radius+locationOnScreen.top)/radius); endRadian = Math.asin((radius+locationOnScreen.left)/radius); unitRadian = (Math.PI / 2+startRadian+endRadian) / (count - 1); direction = Clockwise; startRadian = -startRadian; break; case CORNER_RIGHT_BOTTOM: startRadian = Math.asin((radius+locationOnScreen.right)/radius); endRadian = Math.asin((radius+locationOnScreen.bottom)/radius); unitRadian = (Math.PI / 2+startRadian+endRadian) / (count - 1); direction = Eastern; startRadian = -Math.PI / 2+startRadian; break; case CORNER_RIGHT_TOP: startRadian = Math.asin((radius+locationOnScreen.top)/radius); endRadian = Math.asin((radius+locationOnScreen.right)/radius); unitRadian = (Math.PI / 2+startRadian+endRadian) / (count - 1); direction = Eastern; startRadian = -Math.PI + startRadian; break; default: break; } for (int i = 0; i < count; i++) { PointF pt = new PointF(); if (direction == Eastern) { float offsetX = (float) (position.x + radius * Math.cos(-i * unitRadian + startRadian)); float offsetY = (float) (position.y + radius * Math.sin(-i * unitRadian + startRadian)); pt.set(offsetX, offsetY); } else if (direction == Clockwise) { float offsetX = (float) (position.x + radius * Math.cos(i * unitRadian + startRadian)); float offsetY = (float) (position.y + radius * Math.sin(i * unitRadian + startRadian)); pt.set(offsetX, offsetY); } points.add(pt); } return points; } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { // TODO Auto-generated method stub super.onMeasure(widthMeasureSpec, heightMeasureSpec); radius = this.getWidth() / 2 - 20; position = new Point(this.getWidth() / 2, this.getHeight() / 2); } @Override protected void onDraw(Canvas canvas) { // TODO Auto-generated method stub super.onDraw(canvas); Paint paint = new Paint(); paint.setARGB(255, 207, 0, 112); paint.setTextSize(30); paint.setAntiAlias(true); if (points != null && isShow) { for (int i = 0; i < points.size(); i++) { PointF pt = points.get(i); canvas.drawText("" + i, pt.x, pt.y, paint); } } } @Override public void notifyLocationSetChanged() { // TODO Auto-generated method stub Location locationOnScreen = new Location(mContext , this); LOCATION temp = locationOnScreen.getLocation(); if(location== LOCATION.CENTER && temp == location){ return; } location = temp; points = getDataPoints(views); this.invalidate(); } }
public class GestureSprite implements OnTouchListener, OnGestureListener { private TextView tv2; private ChildsMenuLayout mLayout; private Context mContext; private GestureDetector detector = new GestureDetector(this); private final int MODE_DRAG = 0x1000; private final int MODE_ZOOM = MODE_DRAG + 1; private final int MODE_DEFAULT = -1; private int MODE = MODE_DEFAULT; private PointF oldPosition; private PointF delta; private View[] childViews; private LOCATION location; //************onTouch start*********** private float x = 0, y = 0; private int dx, dy; private int left = 0, top = 0; //************onTouch end*********** private boolean isShowMenu = false; @SuppressLint("NewApi") public GestureSprite(Context context , ChildsMenuLayout layout,TextView tv2){ mLayout = layout; mContext = context; this.tv2 = tv2; } // 用户轻触触摸屏,由1个MotionEvent ACTION_DOWN触发 @Override public boolean onDown(MotionEvent e) { // TODO Auto-generated method stub System.out.println("onDown"); tv2.setText("轻触触摸屏 按下"); return false; } // 用户轻触触摸屏,尚未松开或拖动,由一个1个MotionEvent ACTION_DOWN触发 // 注意和onDown()的区别,强调的是没有松开或者拖动的状态 @Override public void onShowPress(MotionEvent e) { // TODO Auto-generated method stub System.out.println("onShowPress"); tv2.setText("轻触触摸屏,尚未松开或拖动"); } // 用户(轻触触摸屏后)松开,由一个1个MotionEvent ACTION_UP触发 @Override public boolean onSingleTapUp(MotionEvent e) { // TODO Auto-generated method stub System.out.println("onSingleTapUp"); toggleMenu(); tv2.setText("轻触触摸屏后松开"); return false; } // 用户按下触摸屏,并拖动,由1个MotionEvent ACTION_DOWN, 多个ACTION_MOVE触发 @Override public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { // TODO Auto-generated method stub System.out.println("onScroll"); tv2.setText("按下触摸屏,并拖动"); return false; } // 用户长按触摸屏,由多个MotionEvent ACTION_DOWN触发 @Override public void onLongPress(MotionEvent e) { // TODO Auto-generated method stub System.out.println("onLongPress"); tv2.setText("长按触摸屏"); MODE = MODE_DRAG; } // 用户按下触摸屏、快速移动后松开,由1个MotionEvent ACTION_DOWN, 多个ACTION_MOVE, 1个ACTION_UP触发 @Override public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { // TODO Auto-generated method stub float dx = e2.getX() - e1.getX(); float dy = e2.getY() - e1.getY(); if(dx > 0 && Math.abs(dx) > Math.abs(dy)){ System.out.println("onFling right"); tv2.setText("右滑"); }else if(dx < 0 && Math.abs(dx) > Math.abs(dy)){ System.out.println("onFling left"); tv2.setText("左滑"); }else if(dy > 0 && Math.abs(dy) > Math.abs(dx)){ System.out.println("onFling down"); tv2.setText("下滑"); }else if(dy < 0 && Math.abs(dy) > Math.abs(dx)){ tv2.setText("上滑"); System.out.println("onFling up"); } return false; } @Override public boolean onTouch(View v, MotionEvent event) { // TODO Auto-generated method stub detector.onTouchEvent(event); switch (event.getAction() & MotionEvent.ACTION_MASK) { case MotionEvent.ACTION_DOWN: // 指点杆按下 // 将当前的坐标保存为起始点 x = event.getRawX(); y = event.getRawY(); left = mLayout.getLeft(); top = mLayout.getTop(); break; case MotionEvent.ACTION_MOVE: // 指点杆保持按下,并且进行位移 if (MODE == MODE_DRAG) { dx = (int) ((event.getRawX() -x) + left); dy = (int) ((event.getRawY() -y) + top); mLayout.layout(dx, dy, dx + mLayout.getWidth(), dy + mLayout.getHeight()); mLayout.notifyLocationSetChanged(); } break; case MotionEvent.ACTION_UP: // 指点杆离开屏幕 MODE = MODE_DEFAULT; break; case MotionEvent.ACTION_POINTER_UP: // 有手指头离开屏幕,但还有没离开的 break; case MotionEvent.ACTION_POINTER_DOWN: // 如果已经有手指压在屏幕上,又有一个手指压在了屏幕上 break; } return true; } private void toggleMenu(){ isShowMenu = isShowMenu?closeMenu():openMenu(); } private boolean openMenu(){ childViews = new View[6]; mLayout.showChilds(childViews); return true; } private boolean closeMenu(){ // int count = mLayout.getChildCount(); // if(count > 1){ // mLayout.removeViews(1, count); // mLayout.invalidate(); // } mLayout.hideChilds(); return false; } private void setLocation(){ View menuBtn = mLayout.getChildAt(0); }
public class Location { private int screenWidth; private int screenHeight; private int viewWidth; private int viewHeight; public double left; public double top; public double bottom; public double right; private int code; public enum LOCATION{ CENTER,BOUNDARY_LEFT,BOUNDARY_RIGHT,BOUNDARY_TOP,BOUNDARY_BOTTOM,CORNER_LEFT_TOP,CORNER_LEFT_BOTTOM ,CORNER_RIGHT_TOP,CORNER_RIGHT_BOTTOM } public Location(Context context,View view){ screenWidth = ((Activity)context).getWindowManager().getDefaultDisplay().getWidth(); screenHeight = ((Activity)context).getWindowManager().getDefaultDisplay().getHeight(); viewWidth = view.getWidth(); viewHeight = view.getHeight(); int[] array = new int[2]; view.getLocationOnScreen(array); left = array[0]; top = array[1]; right = screenWidth - (left + viewWidth); bottom = screenHeight - (top + viewHeight); } private void onLeft(){ code = left < 0 ? 0x0001 : 0x0; } private void onRight(){ code = right < 0 ? code + 0x0010 : code; } private void onTop(){ code = top < 0 ? code + 0x0100 : code; } private void onBottom(){ code = bottom < 0 ? code + 0x1000 : code; } // private void onCornerLeftTop(){ // code = onLeft()&&onTop() ? code + 1 : code; // } // // private void onCornerLeftBottom(){ // code = onLeft()&&onBottom(); // } // // private void onCornerRightTop(){ // code = onRight()&&onTop(); // } // // private void onCornerRightBottom(){ // code = onRight()&&onBottom(); // } public LOCATION getLocation(){ LOCATION location = null; onLeft(); onRight(); onTop(); onBottom(); switch (code) { case 0x0000: location = LOCATION.CENTER; break; case 0x0001: location = LOCATION.BOUNDARY_LEFT; break; case 0x0010: location = LOCATION.BOUNDARY_RIGHT; break; case 0x0100: location = LOCATION.BOUNDARY_TOP; break; case 0x1000: location = LOCATION.BOUNDARY_BOTTOM; break; case 0x1001: location = LOCATION.CORNER_LEFT_BOTTOM; break; case 0x0101: location = LOCATION.CORNER_LEFT_TOP; break; case 0x1010: location = LOCATION.CORNER_RIGHT_BOTTOM; break; case 0x0110: location = LOCATION.CORNER_RIGHT_TOP; break; default: break; } return location; } }
<RelativeLayout android:layout_width="fill_parent" android:layout_height="fill_parent" > <com.example.template.sprite.ChildsMenuLayout android:id="@+id/layout_bb_menu" android:layout_width="150sp" android:layout_height="150sp" android:layout_centerInParent="true" > <ImageView android:id="@+id/btn_bb_menu" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" android:longClickable="true" android:scaleType="matrix" android:src="@drawable/ic_launcher" /> </com.example.template.sprite.ChildsMenuLayout> </RelativeLayout>
menuBtn = (ImageView) findViewById(R.id.btn_bb_menu); menuBtn.setOnTouchListener(new GestureSprite(this, menuLayout,tv2));
原文地址:http://blog.csdn.net/toyuexinshangwan/article/details/37594329