自定义圆形的groupView

转载请注明转载处:    

自定义圆形的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上的排版都排不了,连选择块都选不了!

不知道大家是怎么发的,怎么排版的!

写这个为了将自己写的东西记下来


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值