自定义控件六:高仿安卓市场桌面悬浮菜单

最近在学习自定义控件,无意中看到了手机上"安卓市场"桌面悬浮菜单,感觉很高大上,所以自己就简单照着样子做了一遍:

首先看原图:

技术分享


涉及到的知识:

①首先这个控件是自定义的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



郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。