最近在学习自定义控件,无意中看到了手机上"安卓市场"桌面悬浮菜单,感觉很高大上,所以自己就简单照着样子做了一遍:
首先看原图:
涉及到的知识:
①首先这个控件是自定义的ViewGroup,需要知道自定义控件中的onMeasure、onLayout的用法。
onMeasure:主要是根据上一级推荐的宽高计算出当前控件的宽高,然后测量当前控件中的每一个子View。
onLayout:为当前控件中的每一个子View进行布局。
②初中所学的三角函数、反三角函数。
例如:
在数学中:sina = 对/斜 这里的a 角度值。
但是在Java中:sina = 对/斜 这里的a 弧度值,所以在java中要得到角度需要用Math.toRadians(a)函数将角度转化为弧度。
好了,回到代码处:
首先是activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#e0000000"
android:gravity="center"
>
<cn.example.com.mycustomwidget_06_circlemenu_01.view.CustomCircleView
android:id="@+id/custom_father_rl"
android:background="@drawable/gears_box_float_main_background"
android:layout_width="355dip"
android:layout_height="301dip">
<RelativeLayout
android:id="@id/custom_circle_mean_center"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageView
android:layout_centerInParent="true"
android:background="@drawable/gears_box_float_big_hexagon"
android:layout_width="167dip"
android:layout_height="187dip" />
<ImageView
android:layout_centerInParent="true"
android:background="@drawable/gears_box_float_big_hexagon_mask"
android:layout_width="152dip"
android:layout_height="172dip" />
</RelativeLayout>
</cn.example.com.mycustomwidget_06_circlemenu_01.view.CustomCircleView>
</LinearLayout>
然后是我们的每个条目的布局item文件circle_mean_item.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:gravity="center"
>
<ImageView
android:id="@id/custom_circle_mean_iv"
android:background="@drawable/gears_box_float_update_pressed"
android:layout_width="20dip"
android:layout_height="20dip" />
<TextView
android:textSize="13sp"
android:id="@id/custom_circle_mean_tv"
android:textColor="@android:color/white"
android:text="升级"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
最后是继承ViewGroup的自定义控件CustomCircleView
package cn.example.com.mycustomwidget_06_circlemenu_01.view;
import android.content.Context;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import java.util.zip.Inflater;
import cn.example.com.mycustomwidget_06_circlemenu_01.R;
/**
* Created by Administrator on 2015/5/27.
*/
public class CustomCircleView extends ViewGroup{
private onMeanItemClickListenner listenner;
//item大小为父控件大小的八分之一
private static final float MEAN_ITEM_SIZE = 1/6f;
//最中间item大小为父控件大小的六分之一
private static final float MEAN_ITEM_CENTER_SIZE = 1/3f;
//item间Padding大小为父控件大小的十二分之一
private static final float MEAN_ITEM_PADDING = 1/12f;
private static final String TAG = CustomCircleView.class.getSimpleName();
//直径
private float diameter;
//mean item大小
float meanItemSize;
//中间的mean item大小
float meanItemCenterSize;
public CustomCircleView(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int mWidth,mHeight;
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
if(widthMode != MeasureSpec.EXACTLY || heightMode != MeasureSpec.EXACTLY){
widthSize = getSuggestedMinimumWidth();
heightSize = getSuggestedMinimumHeight();
widthSize = widthSize == 0 ? getDefaultSize() : widthSize;
heightSize = heightSize == 0 ? getDefaultSize() : heightSize;
setMeasuredDimension(widthSize,heightSize);
}else{
mWidth = mHeight = Math.min(widthSize,heightSize);
setMeasuredDimension(mWidth,mHeight);
}
int measureSpec = 0;
diameter = Math.min(getMeasuredHeight(),getMeasuredWidth());
meanItemSize = diameter * MEAN_ITEM_SIZE;
meanItemCenterSize = diameter * MEAN_ITEM_CENTER_SIZE;
int meanItemMode = MeasureSpec.EXACTLY;
/**
* 依次测量mean item
*/
int meanItemCount = getChildCount();
for(int i=0;i<meanItemCount;i++){
View childView = getChildAt(i);
if(childView.getId() == R.id.custom_circle_mean_center){
measureSpec = MeasureSpec.makeMeasureSpec((int) meanItemCenterSize,meanItemMode);
childView.measure(measureSpec,measureSpec);
}else{
measureSpec = MeasureSpec.makeMeasureSpec((int) meanItemSize,meanItemMode);
childView.measure(measureSpec,measureSpec);
}
}
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
/**
* 依次布局
*/
int meanItemCount = getChildCount();
Log.d(TAG,"meanItemCount:"+meanItemCount);
float angle = 360 / meanItemCount;
float padding = diameter * MEAN_ITEM_PADDING;
float ItemAngle = 0;
//直角三角形的斜边
float hypotenuse = (diameter / 2) - padding - (meanItemSize / 2);
for(int i=0;i<meanItemCount;i++) {
View childView = getChildAt(i);
if (childView.getId() == R.id.custom_circle_mean_center) {
continue;
}else{
ItemAngle %= 360;
int left = (int) (diameter /2 + (int) (Math.cos(Math.toRadians(ItemAngle)) * hypotenuse) - meanItemSize/2) ;
int top = (int) (diameter /2 + (int) (Math.sin(Math.toRadians(ItemAngle)) * hypotenuse) - meanItemSize/2);
int righe = (int) (left+meanItemSize);
int buttom = (int) (top+meanItemSize);
childView.layout(left, top, righe, buttom);
//TODO:如果是画最后一个控件,则合并
if(i == meanItemCount - 2){
ItemAngle+=(angle+angle/2);
}else{
ItemAngle += angle;
}
}
}
View meanCenterItem = findViewById(R.id.custom_circle_mean_center);
int cLeft = (int) (diameter/2 - meanItemCenterSize/2);
int cTop = (int) (diameter/2- meanItemCenterSize/2);
int cRight = (int) (cLeft + meanItemCenterSize);
int cButtom = (int) (cTop + meanItemCenterSize);
meanCenterItem.layout(cLeft, cTop, cRight, cButtom);
meanCenterItem.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
listenner.onCenterMeanItemClick();
}
});
}
/**
* 得到默认布局大小
* @return
*/
private int getDefaultSize(){
WindowManager windowManager = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics displayMetrics = new DisplayMetrics();
windowManager.getDefaultDisplay().getMetrics(displayMetrics);
return Math.min(displayMetrics.widthPixels,displayMetrics.heightPixels);
}
/**
* 设置文字和背景
* @param texts
* @param resIds
*/
public void setTextsAndResIds(String texts[],int resIds[]){
if(texts == null || resIds == null){
throw new IllegalArgumentException("文字和图片不能为空");
}
int itemCount = Math.min(texts.length,resIds.length);
LayoutInflater inflater = LayoutInflater.from(getContext());
for(int i =0;i<itemCount;i++){
final int j = i;
View childView = inflater.inflate(R.layout.circle_mean_item,this,false);
ImageView iv = (ImageView) childView.findViewById(R.id.custom_circle_mean_iv);
TextView tv = (TextView) childView.findViewById(R.id.custom_circle_mean_tv);
iv.setBackgroundResource(resIds[i]);
tv.setText(texts[i]);
iv.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if(listenner != null){
listenner.onMeanItemClick(j);
}
}
});
addView(childView);
}
}
public void setOnMeanItemClickListener(onMeanItemClickListenner listenner){
this.listenner = listenner;
}
/**
* mena item点击事件接口
*/
public interface onMeanItemClickListenner{
void onMeanItemClick(int position);
void onCenterMeanItemClick();
}
}
再最后是我们的MainActivity
package cn.example.com.mycustomwidget_06_circlemenu_01;
import android.app.Activity;
import android.os.Bundle;
import android.widget.Toast;
import cn.example.com.mycustomwidget_06_circlemenu_01.view.CustomCircleView;
import static cn.example.com.mycustomwidget_06_circlemenu_01.view.CustomCircleView.onMeanItemClickListenner;
public class MainActivity extends Activity {
private final String[] texts = new String[]{"软件升级","扫描","垃圾清理","分享","设置"};
// R.drawable.gears_box_float_update_normal
private int[] resIds = new int[]{
R.drawable.updata_selector,
R.drawable.scan_selector,
R.drawable.clean_selector,
R.drawable.share_selector ,
R.drawable.setting_selector
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
CustomCircleView ccv = (CustomCircleView) findViewById(R.id.custom_father_rl);
ccv.setTextsAndResIds(texts,resIds);
ccv.setOnMeanItemClickListener(new CustomCircleView.onMeanItemClickListenner(){
@Override
public void onMeanItemClick(int position){
Toast.makeText(MainActivity.this,texts[position].toString(),Toast.LENGTH_SHORT).show();
}
@Override
public void onCenterMeanItemClick(){
Toast.makeText(MainActivity.this,"center click!",Toast.LENGTH_SHORT).show();
}
});
}
}
到此就结束了!!!看看效果图吧!
源码下载:http://download.csdn.net/detail/yushanfenghailin/8759033
转载请标明出处:http://blog.csdn.net/yushanddddfenghailin/article/details/46299819