网上有很清晰的案例及代码,这篇是通过网上代码整理成自己需求的效果。
首先,自定义ImageView(网上代码):
public class CircleImageView extends ImageView {
private float angle = 0;
private int position = 0;
private String name;
public float getAngle() {
return angle;
}
public void setAngle(float angle) {
this.angle = angle;
}
public int getPosition() {
return position;
}
public void setPosition(int position) {
this.position = position;
}
public String getName(){
return name;
}
public void setName(String name){
this.name = name;
}
/**
* @param context
*/
public CircleImageView(Context context) {
this(context, null);
}
/**
* @param context
* @param attrs
*/
public CircleImageView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
/**
* @param context
* @param attrs
* @param defStyle
*/
public CircleImageView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
if (attrs != null) {
TypedArray a = getContext().obtainStyledAttributes(attrs,
R.styleable.CircleImageView);
name = a.getString(R.styleable.CircleImageView_name);
}
}
}
再次,自定义ViewGroup:
public class CircleLayout extends ViewGroup {
// Event listeners
private OnItemClickListener mOnItemClickListener = null;
private OnItemSelectedListener mOnItemSelectedListener = null;
private OnCenterClickListener mOnCenterClickListener = null;
// Background image
private Bitmap imageOriginal, imageScaled;
private Matrix matrix;
private int mTappedViewsPostition = -1;
private View mTappedView = null;
private int selected = 0;
// Child sizes
private int mMaxChildWidth = 0;
private int mMaxChildHeight = 0;
private int childWidth = 0;
private int childHeight = 0;
// Sizes of the ViewGroup
private int circleWidth, circleHeight;
private int radius = 0;
// Touch detection
private GestureDetector mGestureDetector;
// needed for detecting the inversed rotations
private boolean[] quadrantTouched;
// Settings of the ViewGroup
private boolean allowRotating = true;
private float angle = 90;
private float firstChildPos = 90;
private boolean rotateToCenter = true;
private boolean isRotating = true;
/**
* @param context
*/
public CircleLayout(Context context) {
this(context, null);
}
/**
* @param context
* @param attrs
*/
public CircleLayout(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
/**
* @param context
* @param attrs
* @param defStyle
*/
public CircleLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(attrs);
}
/**
* Initializes the ViewGroup and modifies it's default behavior by the passed attributes
* @param attrs the attributes used to modify default settings
*/
protected void init(AttributeSet attrs) {
mGestureDetector = new GestureDetector(getContext(),
new MyGestureListener());
quadrantTouched = new boolean[] { false, false, false, false, false };
if (attrs != null) {
TypedArray a = getContext().obtainStyledAttributes(attrs,
R.styleable.Circle);
// The angle where the first menu item will be drawn
angle = a.getInt(R.styleable.Circle_firstChildPosition, 90);
firstChildPos = angle;
rotateToCenter = a.getBoolean(R.styleable.Circle_rotateToCenter,
true);
isRotating = a.getBoolean(R.styleable.Circle_isRotating, true);
// If the menu is not rotating then it does not have to be centered
// since it cannot be even moved
if (!isRotating) {
rotateToCenter = false;
}
if (imageOriginal == null) {
int picId = a.getResourceId(
R.styleable.Circle_circleBackground, -1);
// If a background image was set as an attribute,
// retrieve the image
if (picId != -1) {
imageOriginal = BitmapFactory.decodeResource(
getResources(), picId);
}
}
a.recycle();
// initialize the matrix only once
if (matrix == null) {
matrix = new Matrix();
} else {
// not needed, you can also post the matrix immediately to
// restore the old state