转载请注明转载处:
自定义圆形的groupView,先看看效果:
中间有一个加号,点击可以实现隐藏跟现实:
先定义circleView如下:
public CircleView(Context context) { this(context, null); } public CircleView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public CircleView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); initView(); } private void initView() { } 重写onLayout方法跟onMeasure方法
@Override protected void onLayout(boolean changed, int l, int t, int r, int b) { Log.w(TAG , "onLayout"); int childCount = getChildCount(); int radius = getWidth() / 2 - padding ; // 减去padding的半径 int realRadius = getWidth() / 2; // 实际半径 for (int i = 0 ; i < childCount ; i++){ View childView = getChildAt(i); if (i == 0){ // 中心 childView.layout((getWidth() - childView.getMeasuredWidth()) / 2, (getHeight() - childView.getMeasuredHeight()) / 2, (getWidth() + childView.getMeasuredWidth()) / 2, (getHeight() + childView.getMeasuredHeight()) / 2); }else{ float angle = (float)((360.0f / (childCount - 1) * (i - 1) ) / 180 * Math.PI); int startX = getXByAngle(radius , angle , childView); int startY = getYByAngle(radius , angle , childView); childView.layout(realRadius + startX, realRadius + startY, realRadius + startX + childView.getMeasuredWidth(), realRadius + startY + childView.getMeasuredHeight()); Log.i(TAG , "childView.layout l = " + (radius - startX) + "t = " + (radius -startY) + "r = " + (radius - startX + childView.getMeasuredWidth()) + "b = " + (radius - startY + childView.getMeasuredHeight())); } childView.setOnClickListener(this); } } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { Log.w(TAG , "onMeasure"); int countChild = getChildCount(); int specSize_width = MeasureSpec.getSize(widthMeasureSpec); int specSize_height = MeasureSpec.getSize(heightMeasureSpec); setMeasuredDimension(specSize_width, specSize_height); for (int i = 0 ; i < countChild ; i++){ View view = getChildAt(i); measureChild(view , widthMeasureSpec, heightMeasureSpec) ; } }
onMeasure的方法没有什么好说的:
看其onLayout方法:
第一个子view 就是放在中间的那个,如图的那个加号,它是固定放在控件的中间位置。<pre class="java" name="code">if (i == 0){ // 中心 childView.layout((getWidth() - childView.getMeasuredWidth()) / 2, (getHeight() - childView.getMeasuredHeight()) / 2, (getWidth() + childView.getMeasuredWidth()) / 2, (getHeight() + childView.getMeasuredHeight()) / 2); }
然后每一个子view(除了第一个)
根据位置,得到其角度,从角度跟半径得到layout的坐标(相对于中心点(realRadius, realRadius))
private int getYByAngle(float radius, float angle, View view) { float y = (float)(radius * Math.cos(angle)); Log.i(TAG , "getYByAngle radius = " + radius + "angle = " + angle + "y = " + y); return (int)y - view.getMeasuredHeight() / 2; }
private int getXByAngle(float radius, float angle, View view) { float x = (float)(radius * Math.sin(angle)); Log.i(TAG , "getXByAngle radius = " + radius + "angle = " + angle + "x = " + x); return (int)x - view.getMeasuredWidth() / 2; }
最后加上/后者减去(realRadius, realRadius)就可以均匀的loyout在圆上面
到了这里就可以实现如图的效果了。附上xml
<com.example.view.CircleView android:id="@+id/circleView" android:layout_width="500dp" android:layout_height="500dp" > <RelativeLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_centerHorizontal="true" android:background="@drawable/main_menu_button" > <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" android:src="@drawable/menu_icn_plus" /> </RelativeLayout> <ImageView android:layout_width="60dp" android:layout_height="60dp" android:src="@drawable/menu_camera" /> <ImageView android:layout_width="60dp" android:layout_height="60dp" android:src="@drawable/menu_music" /> <ImageView android:layout_width="60dp" android:layout_height="60dp" android:src="@drawable/menu_place" /> <ImageView android:layout_width="60dp" android:layout_height="60dp" android:src="@drawable/menu_sleep" /> <ImageView android:layout_width="60dp" android:layout_height="60dp" android:src="@drawable/menu_thought" /> <ImageView android:layout_width="60dp" android:layout_height="60dp" android:src="@drawable/menu_with" /> <!-- --> </com.example.view.CircleView>
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
即可出现如图的效果:
然后实现点击加号隐藏、显示的功能:
首先实现onclick方法跟注册
public class CircleView extends ViewGroup implements View.OnClickListener
在 onLayout里面加上
childView.setTag(i);
childView.setOnClickListener(this);
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
Log.w(TAG , "onLayout");
int childCount = getChildCount();
int radius = getWidth() / 2 - padding ; // 减去padding的半径
int realRadius = getWidth() / 2; // 实际半径
for (int i = 0 ; i < childCount ; i++){
View childView = getChildAt(i);
if (i == 0){ // 中心
childView.layout((getWidth() - childView.getMeasuredWidth()) / 2, (getHeight() - childView.getMeasuredHeight()) / 2,
(getWidth() + childView.getMeasuredWidth()) / 2, (getHeight() + childView.getMeasuredHeight()) / 2);
}else{
float angle = (float)((360.0f / (childCount - 1) * (i - 1) ) / 180 * Math.PI);
int startX = getXByAngle(radius , angle , childView);
int startY = getYByAngle(radius , angle , childView);
childView.layout(realRadius + startX, realRadius + startY, realRadius + startX + childView.getMeasuredWidth(), realRadius + startY + childView.getMeasuredHeight());
Log.i(TAG , "childView.layout l = " + (radius - startX) + "t = " + (radius -startY) + "r = " + (radius - startX + childView.getMeasuredWidth()) +
"b = " + (radius - startY + childView.getMeasuredHeight()));
}
childView.setTag(i);
childView.setOnClickListener(this);
}
}
实现onClick方法
boolean showMenu = true;
int[] mLocation = new int[2];
@Override
public void onClick(View v) {
int position = (Integer)v.getTag();
if (position == 0){
if (mLocation[0] == 0){
getChildAt(position).getLocationOnScreen(mLocation);
}
if (showMenu){
hideMenu();
}else{
showMenu();
}
ratotaPlus(showMenu , v.getWidth() / 2 , v.getHeight()/2 , v);
showMenu = !showMenu;
}
}
然后hide 很show的 方法
private void ratotaPlus(boolean show, int pivotX , int pivotY, View v) {
Log.i(TAG , "ratotaPlus show = " + show + " pivotX = " + pivotX + "pivotY = " + pivotY );
RotateAnimation mAnimation = null;
if (show){
mAnimation = new RotateAnimation(0, 225 , Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
}else{
mAnimation = new RotateAnimation(225, 0, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
}
mAnimation.setFillAfter(true);
mAnimation.setInterpolator(new AccelerateDecelerateInterpolator());
mAnimation.setDuration(2000);
//v.startAnimation(mAnimation);
v.startAnimation(mAnimation);
}
private void hideMenu() {
Log.i(TAG , "hideMenu now");
int size = getChildCount();
for (int i = 1 ; i <size ; i++){
final View childView = getChildAt(i);
int[] location = new int[2];
childView.getLocationOnScreen(location);
TranslateAnimation animation = new TranslateAnimation(0, getInstanceX(location[0]), 0, getInstanceY(location[1]));
// animation.setInterpolator(new AccelerateDecelerateInterpolator());
animation.setDuration(2000);
// 设计为 true的话childView.setVisibility(View.GONE); 就没有作用了
animation.setFillAfter(false);
animation.setAnimationListener(new AnimationListener() {
@Override
public void onAnimationStart(Animation arg0) {
}
@Override
public void onAnimationRepeat(Animation arg0) {
// TODO Auto-generated method stub
}
@Override
public void onAnimationEnd(Animation arg0) {
childView.setVisibility(View.GONE);
}
});
childView.startAnimation(animation);
}
}
private float getInstanceY(int locationY) {
Log.i(TAG , "locationY = " + locationY + "mLocation[1] = " + mLocation[1]);
return mLocation[1] + 7 - locationY;
}
private float getInstanceX(int locationX) {
Log.i(TAG , "locationX = " + locationX + "mLocation[0] = " + mLocation[0]);
return mLocation[0] + 7 - locationX;
}
private void showMenu() {
Log.i(TAG , "showMenu now");
int size = getChildCount();
for (int i = 1 ; i <size ; i++){
final View childView = getChildAt(i);
int[] location = new int[2];
childView.getLocationOnScreen(location);
TranslateAnimation animation = new TranslateAnimation(getInstanceX(location[0]), 0, getInstanceY(location[1]) , 0);
// animation.setInterpolator(new AccelerateDecelerateInterpolator());
animation.setDuration(2000);
animation.setFillAfter(true);
animation.setAnimationListener(new AnimationListener() {
@Override
public void onAnimationStart(Animation arg0) {
childView.setVisibility(View.GONE);
}
@Override
public void onAnimationRepeat(Animation arg0) {
// TODO Auto-generated method stub
}
@Override
public void onAnimationEnd(Animation arg0) {
childView.setVisibility(View.GONE);
}
});
childView.startAnimation(animation);
}
}
此时点击加号会变成一个用东西的隐藏跟显示,加号会自己旋转,其他都想中间靠拢的动画效果,
值得一说的是方法ratotaPlus() 中的v.startAnimation(mAnimation); 改成 startAnimation(mAnimation);
就会有不一样的效果哦:
旁边的控件是螺旋式的向中间靠拢
最后旁边的子view加上click事件就OK了
增加进口回调
onItemClickListener mItemClickListener = null;
public interface onItemClickListener{
public void onItemClick(int position);
};
public void setOnItemClickListener(onItemClickListener listener){
this.mItemClickListener = listener;
}
在onclick事件里面增加else
@Override
public void onClick(View v) {
int position = (Integer)v.getTag();
if (position == 0){
if (mLocation[0] == 0){
getChildAt(position).getLocationOnScreen(mLocation);
}
if (showMenu){
hideMenu();
}else{
showMenu();
}
ratotaPlus(showMenu , v.getWidth() / 2 , v.getHeight()/2 , v);
showMenu = !showMenu;
}else{
if (null != mItemClickListener && showMenu){
mItemClickListener.onItemClick(position);
}
}
}
在activty中调用就可以了
mCircleView.setOnItemClickListener(new onItemClickListener() {
@Override
public void onItemClick(int position) {
Toast.makeText(MainActivity.this, "mCircleView click position = " + position, Toast.LENGTH_LONG).show();
}
});
最后 我写这个不多,csdn上的排版都排不了,连选择块都选不了!
不知道大家是怎么发的,怎么排版的!
写这个为了将自己写的东西记下来