自定义控件六:高仿安卓市场桌面悬浮菜单
最近在学习自定义控件,无意中看到了手机上"安卓市场"桌面悬浮菜单,感觉很高大上,所以自己就简单照着样子做了一遍:
首先看原图:
涉及到的知识:
①首先这个控件是自定义的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
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。