1 package com.lixu.circlemenu; 2 3 4 import android.app.Activity; 5 import android.os.Bundle; 6 import android.view.View; 7 import android.widget.TextView; 8 import android.widget.Toast; 9 10 import com.lixu.circlemenu.view.CircleImageView; 11 import com.lixu.circlemenu.view.CircleLayout; 12 import com.lixu.circlemenu.view.CircleLayout.OnItemClickListener; 13 import com.lixu.circlemenu.view.CircleLayout.OnItemSelectedListener; 14 import com.szugyi.circlemenu.R; 15 16 public class MainActivity extends Activity implements OnItemSelectedListener, OnItemClickListener{ 17 18 private TextView selectedTextView; 19 20 @Override 21 protected void onCreate(Bundle savedInstanceState) { 22 super.onCreate(savedInstanceState); 23 setContentView(R.layout.activity_main); 24 25 CircleLayout circleMenu = (CircleLayout)findViewById(R.id.main_circle_layout); 26 circleMenu.setOnItemSelectedListener(this); 27 circleMenu.setOnItemClickListener(this); 28 29 //这个TextView仅仅作为演示转盘按钮以何为默认的选中项, 30 //默认的最底部的那一条被选中,然后显示到该TextView中。 31 selectedTextView = (TextView)findViewById(R.id.main_selected_textView); 32 selectedTextView.setText(((CircleImageView)circleMenu.getSelectedItem()).getName()); 33 } 34 35 //圆盘转动到底部,则认为该条目被选中 36 @Override 37 public void onItemSelected(View view, int position, long id, String name) { 38 selectedTextView.setText(name); 39 } 40 41 //选择了转盘中的某一条。 42 @Override 43 public void onItemClick(View view, int position, long id, String name) { 44 Toast.makeText(getApplicationContext(), getResources().getString(R.string.start_app) + " " + name, Toast.LENGTH_SHORT).show(); 45 } 46 }
引用两个开源类:
1 package com.lixu.circlemenu.view; 2 3 /* 4 * Copyright 2013 Csaba Szugyiczki 5 * 6 * Licensed under the Apache License, Version 2.0 (the "License"); 7 * you may not use this file except in compliance with the License. 8 * You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, software 13 * distributed under the License is distributed on an "AS IS" BASIS, 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 * See the License for the specific language governing permissions and 16 * limitations under the License. 17 */ 18 19 import android.content.Context; 20 import android.content.res.TypedArray; 21 import android.util.AttributeSet; 22 import android.widget.ImageView; 23 24 import com.szugyi.circlemenu.R; 25 26 /** 27 * 28 * @author Szugyi 29 * Custom ImageView for the CircleLayout class. 30 * Makes it possible for the image to have an angle, position and a name. 31 * Angle is used for the positioning in the circle menu. 32 */ 33 public class CircleImageView extends ImageView { 34 35 private float angle = 0; 36 private int position = 0; 37 private String name; 38 39 public float getAngle() { 40 return angle; 41 } 42 43 public void setAngle(float angle) { 44 this.angle = angle; 45 } 46 47 public int getPosition() { 48 return position; 49 } 50 51 public void setPosition(int position) { 52 this.position = position; 53 } 54 55 public String getName(){ 56 return name; 57 } 58 59 public void setName(String name){ 60 this.name = name; 61 } 62 63 /** 64 * @param context 65 */ 66 public CircleImageView(Context context) { 67 this(context, null); 68 } 69 70 /** 71 * @param context 72 * @param attrs 73 */ 74 public CircleImageView(Context context, AttributeSet attrs) { 75 this(context, attrs, 0); 76 } 77 78 /** 79 * @param context 80 * @param attrs 81 * @param defStyle 82 */ 83 public CircleImageView(Context context, AttributeSet attrs, int defStyle) { 84 super(context, attrs, defStyle); 85 if (attrs != null) { 86 TypedArray a = getContext().obtainStyledAttributes(attrs, 87 R.styleable.CircleImageView); 88 89 name = a.getString(R.styleable.CircleImageView_name); 90 } 91 } 92 93 }
1 package com.lixu.circlemenu.view; 2 3 import com.szugyi.circlemenu.R; 4 5 /* 6 * Copyright 2013 Csaba Szugyiczki 7 * 8 * Licensed under the Apache License, Version 2.0 (the "License"); 9 * you may not use this file except in compliance with the License. 10 * You may obtain a copy of the License at 11 * 12 * http://www.apache.org/licenses/LICENSE-2.0 13 * 14 * Unless required by applicable law or agreed to in writing, software 15 * distributed under the License is distributed on an "AS IS" BASIS, 16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 * See the License for the specific language governing permissions and 18 * limitations under the License. 19 */ 20 21 import android.content.Context; 22 import android.content.res.TypedArray; 23 import android.graphics.Bitmap; 24 import android.graphics.BitmapFactory; 25 import android.graphics.Canvas; 26 import android.graphics.Matrix; 27 import android.util.AttributeSet; 28 import android.view.GestureDetector; 29 import android.view.GestureDetector.SimpleOnGestureListener; 30 import android.view.MotionEvent; 31 import android.view.View; 32 import android.view.ViewGroup; 33 34 35 /** 36 * 37 * @author Szugyi 38 * Creates a rotatable circle menu which can be parameterized by custom attributes. 39 * Handles touches and gestures to make the menu rotatable, and to make the 40 * menu items selectable and clickable. 41 * 42 */ 43 public class CircleLayout extends ViewGroup { 44 // Event listeners 45 private OnItemClickListener mOnItemClickListener = null; 46 private OnItemSelectedListener mOnItemSelectedListener = null; 47 private OnCenterClickListener mOnCenterClickListener = null; 48 49 // Background image 50 private Bitmap imageOriginal, imageScaled; 51 private Matrix matrix; 52 53 private int mTappedViewsPostition = -1; 54 private View mTappedView = null; 55 private int selected = 0; 56 57 // Child sizes 58 private int mMaxChildWidth = 0; 59 private int mMaxChildHeight = 0; 60 private int childWidth = 0; 61 private int childHeight = 0; 62 63 // Sizes of the ViewGroup 64 private int circleWidth, circleHeight; 65 private int radius = 0; 66 67 // Touch detection 68 private GestureDetector mGestureDetector; 69 // needed for detecting the inversed rotations 70 private boolean[] quadrantTouched; 71 72 // Settings of the ViewGroup 73 private boolean allowRotating = true; 74 private float angle = 90; 75 private float firstChildPos = 90; 76 private boolean rotateToCenter = true; 77 private boolean isRotating = true; 78 79 /** 80 * @param context 81 */ 82 public CircleLayout(Context context) { 83 this(context, null); 84 } 85 86 /** 87 * @param context 88 * @param attrs 89 */ 90 public CircleLayout(Context context, AttributeSet attrs) { 91 this(context, attrs, 0); 92 } 93 94 /** 95 * @param context 96 * @param attrs 97 * @param defStyle 98 */ 99 public CircleLayout(Context context, AttributeSet attrs, int defStyle) { 100 super(context, attrs, defStyle); 101 init(attrs); 102 } 103 104 /** 105 * Initializes the ViewGroup and modifies it's default behavior by the passed attributes 106 * @param attrs the attributes used to modify default settings 107 */ 108 protected void init(AttributeSet attrs) { 109 mGestureDetector = new GestureDetector(getContext(), 110 new MyGestureListener()); 111 quadrantTouched = new boolean[] { false, false, false, false, false }; 112 113 if (attrs != null) { 114 TypedArray a = getContext().obtainStyledAttributes(attrs, 115 R.styleable.Circle); 116 117 // The angle where the first menu item will be drawn 118 angle = a.getInt(R.styleable.Circle_firstChildPosition, 90); 119 firstChildPos = angle; 120 121 rotateToCenter = a.getBoolean(R.styleable.Circle_rotateToCenter, 122 true); 123 isRotating = a.getBoolean(R.styleable.Circle_isRotating, true); 124 125 // If the menu is not rotating then it does not have to be centered 126 // since it cannot be even moved 127 if (!isRotating) { 128 rotateToCenter = false; 129 } 130 131 if (imageOriginal == null) { 132 int picId = a.getResourceId( 133 R.styleable.Circle_circleBackground, -1); 134 135 // If a background image was set as an attribute, 136 // retrieve the image 137 if (picId != -1) { 138 imageOriginal = BitmapFactory.decodeResource( 139 getResources(), picId); 140 } 141 } 142 143 a.recycle(); 144 145 // initialize the matrix only once 146 if (matrix == null) { 147 matrix = new Matrix(); 148 } else { 149 // not needed, you can also post the matrix immediately to 150 // restore the old state 151 matrix.reset(); 152 } 153 // Needed for the ViewGroup to be drawn 154 setWillNotDraw(false); 155 } 156 } 157 158 /** 159 * Returns the currently selected menu 160 * @return the view which is currently the closest to the start position 161 */ 162 public View getSelectedItem() { 163 return (selected >= 0) ? getChildAt(selected) : null; 164 } 165 166 @Override 167 protected void onDraw(Canvas canvas) { 168 // the sizes of the ViewGroup 169 circleHeight = getHeight(); 170 circleWidth = getWidth(); 171 172 if (imageOriginal != null) { 173 // Scaling the size of the background image 174 if (imageScaled == null) { 175 matrix = new Matrix(); 176 float sx = (((radius + childWidth / 4) * 2) / (float) imageOriginal 177 .getWidth()); 178 float sy = (((radius + childWidth / 4) * 2) / (float) imageOriginal 179 .getHeight()); 180 matrix.postScale(sx, sy); 181 imageScaled = Bitmap.createBitmap(imageOriginal, 0, 0, 182 imageOriginal.getWidth(), imageOriginal.getHeight(), 183 matrix, false); 184 } 185 186 if (imageScaled != null) { 187 // Move the background to the center 188 int cx = (circleWidth - imageScaled.getWidth()) / 2; 189 int cy = (circleHeight - imageScaled.getHeight()) / 2; 190 191 Canvas g = canvas; 192 canvas.rotate(0, circleWidth / 2, circleHeight / 2); 193 g.drawBitmap(imageScaled, cx, cy, null); 194 195 } 196 } 197 } 198 199 @Override 200 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 201 mMaxChildWidth = 0; 202 mMaxChildHeight = 0; 203 204 // Measure once to find the maximum child size. 205 int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec( 206 MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.AT_MOST); 207 int childHeightMeasureSpec = MeasureSpec.makeMeasureSpec( 208 MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.AT_MOST); 209 210 final int count = getChildCount(); 211 for (int i = 0; i < count; i++) { 212 final View child = getChildAt(i); 213 if (child.getVisibility() == GONE) { 214 continue; 215 } 216 217 child.measure(childWidthMeasureSpec, childHeightMeasureSpec); 218 219 mMaxChildWidth = Math.max(mMaxChildWidth, child.getMeasuredWidth()); 220 mMaxChildHeight = Math.max(mMaxChildHeight, 221 child.getMeasuredHeight()); 222 } 223 224 // Measure again for each child to be exactly the same size. 225 childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(mMaxChildWidth, 226 MeasureSpec.EXACTLY); 227 childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(mMaxChildHeight, 228 MeasureSpec.EXACTLY); 229 230 for (int i = 0; i < count; i++) { 231 final View child = getChildAt(i); 232 if (child.getVisibility() == GONE) { 233 continue; 234 } 235 236 child.measure(childWidthMeasureSpec, childHeightMeasureSpec); 237 } 238 239 setMeasuredDimension(resolveSize(mMaxChildWidth, widthMeasureSpec), 240 resolveSize(mMaxChildHeight, heightMeasureSpec)); 241 } 242 243 @Override 244 protected void onLayout(boolean changed, int l, int t, int r, int b) { 245 int layoutWidth = r - l; 246 int layoutHeight = b - t; 247 248 // Laying out the child views 249 final int childCount = getChildCount(); 250 int left, top; 251 radius = (layoutWidth <= layoutHeight) ? layoutWidth / 3 252 : layoutHeight / 3; 253 254 childWidth = (int) (radius / 1.5); 255 childHeight = (int) (radius / 1.5); 256 257 float angleDelay = 360 / getChildCount(); 258 259 for (int i = 0; i < childCount; i++) { 260 final CircleImageView child = (CircleImageView) getChildAt(i); 261 if (child.getVisibility() == GONE) { 262 continue; 263 } 264 265 if (angle > 360) { 266 angle -= 360; 267 } else { 268 if (angle < 0) { 269 angle += 360; 270 } 271 } 272 273 child.setAngle(angle); 274 child.setPosition(i); 275 276 left = Math 277 .round((float) (((layoutWidth / 2) - childWidth / 2) + radius 278 * Math.cos(Math.toRadians(angle)))); 279 top = Math 280 .round((float) (((layoutHeight / 2) - childHeight / 2) + radius 281 * Math.sin(Math.toRadians(angle)))); 282 283 child.layout(left, top, left + childWidth, top + childHeight); 284 angle += angleDelay; 285 } 286 } 287 288 /** 289 * Rotate the buttons. 290 * 291 * @param degrees The degrees, the menu items should get rotated. 292 */ 293 private void rotateButtons(float degrees) { 294 int left, top, childCount = getChildCount(); 295 float angleDelay = 360 / childCount; 296 angle += degrees; 297 298 if (angle > 360) { 299 angle -= 360; 300 } else { 301 if (angle < 0) { 302 angle += 360; 303 } 304 } 305 306 for (int i = 0; i < childCount; i++) { 307 if (angle > 360) { 308 angle -= 360; 309 } else { 310 if (angle < 0) { 311 angle += 360; 312 } 313 } 314 315 final CircleImageView child = (CircleImageView) getChildAt(i); 316 if (child.getVisibility() == GONE) { 317 continue; 318 } 319 left = Math 320 .round((float) (((circleWidth / 2) - childWidth / 2) + radius 321 * Math.cos(Math.toRadians(angle)))); 322 top = Math 323 .round((float) (((circleHeight / 2) - childHeight / 2) + radius 324 * Math.sin(Math.toRadians(angle)))); 325 326 child.setAngle(angle); 327 328 if (Math.abs(angle - firstChildPos) < (angleDelay / 2) 329 && selected != child.getPosition()) { 330 selected = child.getPosition(); 331 332 if (mOnItemSelectedListener != null && rotateToCenter) { 333 mOnItemSelectedListener.onItemSelected(child, selected, 334 child.getId(), child.getName()); 335 } 336 } 337 338 child.layout(left, top, left + childWidth, top + childHeight); 339 angle += angleDelay; 340 } 341 } 342 343 /** 344 * @return The angle of the unit circle with the image view's center 345 */ 346 private double getAngle(double xTouch, double yTouch) { 347 double x = xTouch - (circleWidth / 2d); 348 double y = circleHeight - yTouch - (circleHeight / 2d); 349 350 switch (getQuadrant(x, y)) { 351 case 1: 352 return Math.asin(y / Math.hypot(x, y)) * 180 / Math.PI; 353 354 case 2: 355 case 3: 356 return 180 - (Math.asin(y / Math.hypot(x, y)) * 180 / Math.PI); 357 358 case 4: 359 return 360 + Math.asin(y / Math.hypot(x, y)) * 180 / Math.PI; 360 361 default: 362 // ignore, does not happen 363 return 0; 364 } 365 } 366 367 /** 368 * @return The selected quadrant. 369 */ 370 private static int getQuadrant(double x, double y) { 371 if (x >= 0) { 372 return y >= 0 ? 1 : 4; 373 } else { 374 return y >= 0 ? 2 : 3; 375 } 376 } 377 378 private double startAngle; 379 380 @Override 381 public boolean onTouchEvent(MotionEvent event) { 382 if (isEnabled()) { 383 if (isRotating) { 384 switch (event.getAction()) { 385 case MotionEvent.ACTION_DOWN: 386 387 // reset the touched quadrants 388 for (int i = 0; i < quadrantTouched.length; i++) { 389 quadrantTouched[i] = false; 390 } 391 392 allowRotating = false; 393 394 startAngle = getAngle(event.getX(), event.getY()); 395 break; 396 case MotionEvent.ACTION_MOVE: 397 double currentAngle = getAngle(event.getX(), event.getY()); 398 rotateButtons((float) (startAngle - currentAngle)); 399 startAngle = currentAngle; 400 break; 401 case MotionEvent.ACTION_UP: 402 allowRotating = true; 403 rotateViewToCenter((CircleImageView) getChildAt(selected), 404 false); 405 break; 406 } 407 } 408 409 // set the touched quadrant to true 410 quadrantTouched[getQuadrant(event.getX() - (circleWidth / 2), 411 circleHeight - event.getY() - (circleHeight / 2))] = true; 412 mGestureDetector.onTouchEvent(event); 413 return true; 414 } 415 return false; 416 } 417 418 private class MyGestureListener extends SimpleOnGestureListener { 419 @Override 420 public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, 421 float velocityY) { 422 if (!isRotating) { 423 return false; 424 } 425 // get the quadrant of the start and the end of the fling 426 int q1 = getQuadrant(e1.getX() - (circleWidth / 2), circleHeight 427 - e1.getY() - (circleHeight / 2)); 428 int q2 = getQuadrant(e2.getX() - (circleWidth / 2), circleHeight 429 - e2.getY() - (circleHeight / 2)); 430 431 // the inversed rotations 432 if ((q1 == 2 && q2 == 2 && Math.abs(velocityX) < Math 433 .abs(velocityY)) 434 || (q1 == 3 && q2 == 3) 435 || (q1 == 1 && q2 == 3) 436 || (q1 == 4 && q2 == 4 && Math.abs(velocityX) > Math 437 .abs(velocityY)) 438 || ((q1 == 2 && q2 == 3) || (q1 == 3 && q2 == 2)) 439 || ((q1 == 3 && q2 == 4) || (q1 == 4 && q2 == 3)) 440 || (q1 == 2 && q2 == 4 && quadrantTouched[3]) 441 || (q1 == 4 && q2 == 2 && quadrantTouched[3])) { 442 443 CircleLayout.this.post(new FlingRunnable(-1 444 * (velocityX + velocityY))); 445 } else { 446 // the normal rotation 447 CircleLayout.this 448 .post(new FlingRunnable(velocityX + velocityY)); 449 } 450 451 return true; 452 453 } 454 455 @Override 456 public boolean onSingleTapUp(MotionEvent e) { 457 mTappedViewsPostition = pointToPosition(e.getX(), e.getY()); 458 if (mTappedViewsPostition >= 0) { 459 mTappedView = getChildAt(mTappedViewsPostition); 460 mTappedView.setPressed(true); 461 } else { 462 float centerX = circleWidth / 2; 463 float centerY = circleHeight / 2; 464 465 if (e.getX() < centerX + (childWidth / 2) 466 && e.getX() > centerX - childWidth / 2 467 && e.getY() < centerY + (childHeight / 2) 468 && e.getY() > centerY - (childHeight / 2)) { 469 if (mOnCenterClickListener != null) { 470 mOnCenterClickListener.onCenterClick(); 471 return true; 472 } 473 } 474 } 475 476 if (mTappedView != null) { 477 CircleImageView view = (CircleImageView) (mTappedView); 478 if (selected != mTappedViewsPostition) { 479 rotateViewToCenter(view, false); 480 if (!rotateToCenter) { 481 if (mOnItemSelectedListener != null) { 482 mOnItemSelectedListener.onItemSelected(mTappedView, 483 mTappedViewsPostition, mTappedView.getId(), view.getName()); 484 } 485 486 if (mOnItemClickListener != null) { 487 mOnItemClickListener.onItemClick(mTappedView, 488 mTappedViewsPostition, mTappedView.getId(), view.getName()); 489 } 490 } 491 } else { 492 rotateViewToCenter(view, false); 493 494 if (mOnItemClickListener != null) { 495 mOnItemClickListener.onItemClick(mTappedView, 496 mTappedViewsPostition, mTappedView.getId(), view.getName()); 497 } 498 } 499 return true; 500 } 501 return super.onSingleTapUp(e); 502 } 503 } 504 505 /** 506 * Rotates the given view to the center of the menu. 507 * @param view the view to be rotated to the center 508 * @param fromRunnable if the method is called from the runnable which animates the rotation 509 * then it should be true, otherwise false 510 */ 511 private void rotateViewToCenter(CircleImageView view, boolean fromRunnable) { 512 if (rotateToCenter) { 513 float velocityTemp = 1; 514 float destAngle = (float) (firstChildPos - view.getAngle()); 515 float startAngle = 0; 516 int reverser = 1; 517 518 if (destAngle < 0) { 519 destAngle += 360; 520 } 521 522 if (destAngle > 180) { 523 reverser = -1; 524 destAngle = 360 - destAngle; 525 } 526 527 while (startAngle < destAngle) { 528 startAngle += velocityTemp / 75; 529 velocityTemp *= 1.0666F; 530 } 531 532 CircleLayout.this.post(new FlingRunnable(reverser * velocityTemp, 533 !fromRunnable)); 534 } 535 } 536 537 /** 538 * A {@link Runnable} for animating the menu rotation. 539 */ 540 private class FlingRunnable implements Runnable { 541 542 private float velocity; 543 float angleDelay; 544 boolean isFirstForwarding = true; 545 546 public FlingRunnable(float velocity) { 547 this(velocity, true); 548 } 549 550 public FlingRunnable(float velocity, boolean isFirst) { 551 this.velocity = velocity; 552 this.angleDelay = 360 / getChildCount(); 553 this.isFirstForwarding = isFirst; 554 } 555 556 public void run() { 557 if (Math.abs(velocity) > 5 && allowRotating) { 558 if (rotateToCenter) { 559 if (!(Math.abs(velocity) < 200 && (Math.abs(angle 560 - firstChildPos) 561 % angleDelay < 2))) { 562 rotateButtons(velocity / 75); 563 velocity /= 1.0666F; 564 565 CircleLayout.this.post(this); 566 } 567 } else { 568 rotateButtons(velocity / 75); 569 velocity /= 1.0666F; 570 571 CircleLayout.this.post(this); 572 } 573 } else { 574 if (isFirstForwarding) { 575 isFirstForwarding = false; 576 CircleLayout.this.rotateViewToCenter( 577 (CircleImageView) getChildAt(selected), true); 578 } 579 } 580 } 581 } 582 583 private int pointToPosition(float x, float y) { 584 585 for (int i = 0; i < getChildCount(); i++) { 586 587 View item = (View) getChildAt(i); 588 if (item.getLeft() < x && item.getRight() > x & item.getTop() < y 589 && item.getBottom() > y) { 590 return i; 591 } 592 593 } 594 return -1; 595 } 596 597 public void setOnItemClickListener(OnItemClickListener onItemClickListener) { 598 this.mOnItemClickListener = onItemClickListener; 599 } 600 601 public interface OnItemClickListener { 602 void onItemClick(View view, int position, long id, String name); 603 } 604 605 public void setOnItemSelectedListener( 606 OnItemSelectedListener onItemSelectedListener) { 607 this.mOnItemSelectedListener = onItemSelectedListener; 608 } 609 610 public interface OnItemSelectedListener { 611 void onItemSelected(View view, int position, long id, String name); 612 } 613 614 public interface OnCenterClickListener { 615 void onCenterClick(); 616 } 617 618 public void setOnCenterClickListener( 619 OnCenterClickListener onCenterClickListener) { 620 this.mOnCenterClickListener = onCenterClickListener; 621 } 622 }
xml文件:
1 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 2 xmlns:circle="http://schemas.android.com/apk/res/com.szugyi.circlemenu" 3 xmlns:tools="http://schemas.android.com/tools" 4 android:layout_width="match_parent" 5 android:layout_height="match_parent" 6 tools:context=".MainActivity" > 7 8 <com.lixu.circlemenu.view.CircleLayout 9 android:id="@+id/main_circle_layout" 10 android:layout_width="fill_parent" 11 android:layout_height="fill_parent" 12 android:layout_above="@+id/main_selected_textView" 13 android:layout_gravity="center_horizontal" 14 circle:firstChildPosition="South" 15 circle:rotateToCenter="true" 16 circle:isRotating="true" > 17 <!-- circle:circleBackground="@drawable/green" > --> 18 19 20 <com.lixu.circlemenu.view.CircleImageView 21 android:id="@+id/main_facebook_image" 22 android:layout_width="35dp" 23 android:layout_height="35dp" 24 android:src="@drawable/icon_facebook" 25 circle:name="@string/facebook" /> 26 27 <com.lixu.circlemenu.view.CircleImageView 28 android:id="@+id/main_myspace_image" 29 android:layout_width="wrap_content" 30 android:layout_height="wrap_content" 31 android:src="@drawable/icon_myspace" 32 circle:name="@string/myspace" /> 33 34 <com.lixu.circlemenu.view.CircleImageView 35 android:id="@+id/main_google_image" 36 android:layout_width="wrap_content" 37 android:layout_height="wrap_content" 38 android:src="@drawable/icon_google" 39 circle:name="@string/google" /> 40 41 <com.lixu.circlemenu.view.CircleImageView 42 android:id="@+id/main_linkedin_image" 43 android:layout_width="wrap_content" 44 android:layout_height="wrap_content" 45 android:src="@drawable/icon_linkedin" 46 circle:name="@string/linkedin" /> 47 48 <com.lixu.circlemenu.view.CircleImageView 49 android:id="@+id/main_twitter_image" 50 android:layout_width="wrap_content" 51 android:layout_height="wrap_content" 52 android:src="@drawable/icon_twitter" 53 circle:name="@string/twitter" /> 54 55 <com.lixu.circlemenu.view.CircleImageView 56 android:id="@+id/main_wordpress_image" 57 android:layout_width="wrap_content" 58 android:layout_height="wrap_content" 59 android:src="@drawable/icon_wordpress" 60 circle:name="@string/wordpress" /> 61 </com.lixu.circlemenu.view.CircleLayout> 62 63 <TextView 64 android:id="@+id/main_selected_textView" 65 android:layout_width="wrap_content" 66 android:layout_height="wrap_content" 67 android:layout_alignParentBottom="true" 68 android:layout_centerHorizontal="true" 69 android:layout_marginBottom="50dp" 70 android:textAppearance="?android:attr/textAppearanceLarge" /> 71 72 </RelativeLayout>
运行效果: