转载请注明转载处:
自定义圆形的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
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上的排版都排不了,连选择块都选不了!
不知道大家是怎么发的,怎么排版的!
写这个为了将自己写的东西记下来