圆形菜单View

效果图:


这是建行APP的一个界面,最近在学习自定义view,所以记录一下心得。

分析:

① 因为该view里面可以盛放很多子view,所以要继承ViewGroup,而不是view。
② view中的子孩子数据是不确定的,也就是从服务器上请求下来的数据,所以我们在使用该view的时候,要进行设置数据的操作。
③ 当使用者设置数据,肯定是一组中必须要有一个text和一个ImageView这两个数据,那么这个是确定的,所以我们可以先写出子view的xml,通过遍历传递过来的数据,一个个将子view 添加到viewGroup中。
④ 将子view添加到viewGroup中,要对子view进行测量以及摆放操作。
⑤测量,也就是重写onMeasure方法,需要注意的几点:
a.只是测量自身,不会测量子孩子。
b.MeasureSpec 是由32位int组成的,前两位是数据模式Mode,剩余是数据大小Size。
MeasureSpec = size + mode
c.其中Mode分为三种:
UNSPECIFIED数值为0<<30(后30位)
EXACTLY数值为1<<30, 明确的尺寸,如XXXdp,MATCH_PARENT
AT_MOST数值为2<<30,至多为多少,如WRAP_CONTENT,若控件本身没有默认尺寸,则系统会尽可能的把空间赋予控件,为MATCH_PARENT ~~~~~《注意这点》
⑥布局排列 onLayout
确定子view的位置,左上右下,在计算的时候,会使用到角度值,注意该角度对应每一个view的变化。

onMeasure方法中常用API:

setMeasureDimension(width,height):设置控件的最终尺寸
MeasureSpec spec= MeasureSpec.makeMeasureSpec(size,mode);用于指定MeasureSpec
MeasureSpec.getSize(measureSpec);通过MeasureSpec获取size
MeasureSpec.getMode(measureSpec);通过MeasureSpec获取mode
getSuggestedMinimumWidth():获得背景图的宽度,如果没有背景,则返回值为0
····

开撸:

1·创建一个类,继承ViewGroup,实现构造:
public class MenuView extends ViewGroup {
  private String TAG = "MenuView";

  public MenuView(Context context) {
      this(context,null);
  }

  public MenuView(Context context, AttributeSet attrs) {
      this(context, attrs,0);
  }

  public MenuView(Context context, AttributeSet attrs, int defStyleAttr) {
      super(context, attrs, defStyleAttr);
  }
2.xml布局中使用
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              android:background="@color/colorWhite3"
              android:gravity="center"
              android:orientation="vertical">

    <zyh.demo.view.MenuView
        android:id="@+id/frg_circle_mv"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@drawable/circle_bg"/>
</LinearLayout>
3.调用者中使用
private String[] texts = new String[]{"安全", "服务", "理财",
            "汇款", "账户", "信用"};
private int[] imgs = new int[]{R.drawable.home_mbank_1_normal,
            R.drawable.home_mbank_2_normal, R.drawable.home_mbank_3_normal,
            R.drawable.home_mbank_4_normal, R.drawable.home_mbank_5_normal,
            R.drawable.home_mbank_6_normal};

.....省略部分代码......

View view = inflater.inflate(R.layout.frg_circle, null, false);
MenuView  menuView = (MenuView) view.findViewById(R.id.frg_circle_mv);
//给viewGroup设置数据,当然这个数据是模拟的假数据,不过要保证这两组数据要保持一致,不然会报角标越界
menuView.setData(texts,imgs);
4.对MenuView进行数据处理
 public void setData(String[] texts, int[] imgs) {
        for (int i = 0; i <texts.length ; i++) {
             // 遍历使用者传递过来的数据,创建一个子view视图,并转换成view。
            View view = View.inflate(getContext(), R.layout.view_menu, null);
            TextView textView = (TextView) view.findViewById(R.id.menu_tv);
            ImageView imageView = (ImageView) view.findViewById(R.id.menu_iv);
            // 设置数据
            textView.setText(texts[i]);
            imageView.setImageResource(imgs[i]);
            //添加到viewGroup中
            addView(view);
        }
    }

子view视图

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:orientation="vertical"
              android:layout_width="10dp"
              android:layout_height="10dp">
    <TextView
        android:id="@+id/menu_tv"
        android:layout_gravity="center"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="sss"
        android:textColor="@color/colorWhite"/>
    <ImageView
        android:id="@+id/menu_iv"
        android:layout_gravity="center"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/home_mbank_1_normal"/>
</LinearLayout>
5.重写onLayout方法
    private int d = 350; //初次定义背景的直径,后期会有改动   
    /**弧度*/
    private int stratAngle = 0;
    @Override
    protected void onLayout(boolean b, int i, int i1, int i2, int i3) {

        for (int j = 0; j < getChildCount(); j++) {
            View childView = getChildAt(j);
            // 计算子view的宽度
            int childWidth = childView.getMeasuredWidth();
            // 自定义控件所在的圆到子视图之间的距离。
            float temp = d / 3.0f;
            // 动态的计算子view的左上右下
            int left = (int) (d /2 + Math.round(temp * Math.cos(Math.toRadians(stratAngle))) - childWidth/2);
            int right = left + childWidth;
            int top = (int) (d / 2 + Math.round(temp * Math.sin(Math.toRadians(stratAngle))) - childWidth / 2);
            int buttom = top + childWidth;
            // 确定view布局的位置
            childView.layout(left,top,right,buttom);
            //stratAngle弧度是一个累加过程,不是固定的值
            stratAngle += 360 / getChildCount();
        }
    }
6.重写onMeasure方法,如果不重写该方法的话,会导致看不到子view,因为没有测量
      @Override
      protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
      // 测量父布局
        //android:gravity="center"
      //  super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int measuredWidth = 0;
        int measuredHeight = 0;

        //获取测量模式及测量的大小;
        int mode = MeasureSpec.getMode(widthMeasureSpec);
        int size = MeasureSpec.getSize(widthMeasureSpec);

        // 判断测量模式
        if(mode != MeasureSpec.EXACTLY) {
            // 这个是不确定的值,最大为 wrap_content
            // 有没有背景?
            //获取背景
            int suggestedMinimumWidth = getSuggestedMinimumWidth();
            if (suggestedMinimumWidth == 0) {   // 没有背景图
                //默认宽度就是屏幕大小
                measuredHeight = measuredWidth = getDefaultWidth();
            }else {
                measuredHeight = measuredWidth = Math.min(suggestedMinimumWidth,getDefaultWidth());
            }


        }else{      // 固定的数据,match_parent  或者 xxxdp
            //如果是填充父窗体,也就是屏幕的宽高的较小值,《保证在屏幕可见范围内》
            // 如果是固定的数值的话,也就是size,如果用户传入大无穷的数据,也是不可见的,所以屏幕的大小是一个界限。最大不过屏幕的大小
            measuredHeight = measuredWidth = Math.min(size,getDefaultWidth());
        }

        d = measuredHeight;
        //设置控件的最终尺寸
        Log.e(TAG,"measuredHeight:"+measuredHeight);
        setMeasuredDimension(measuredWidth,measuredHeight);  //最终目的就是它~~~~~·

      //遍历所有的子孩子,进行测量
        for (int i = 0; i < getChildCount(); i++) {
            View childAt = getChildAt(i);
                // 对子孩子指定MeasureSpec,一定要指定子孩子的MeasureSpec,否则子孩子无法测量,进而不知道子孩子的摆放位置。
            int makeMeasureSpec = MeasureSpec.makeMeasureSpec(d / 5, MeasureSpec.EXACTLY);
            childAt.measure(makeMeasureSpec,makeMeasureSpec);
        }
    }


    /**
     * 获取屏幕的宽高的较小值
     * */
    private int getDefaultWidth (){
        DisplayMetrics displayMetrics = getResources().getDisplayMetrics();
        int width = displayMetrics.widthPixels;
        int height = displayMetrics.heightPixels;
        return Math.min(width,height);
    }

这样一步步的,自定义view就实现了,明个周六,又可以休息啦~~~~·加油 !!!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,711评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,932评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,770评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,799评论 1 271
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,697评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,069评论 1 276
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,535评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,200评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,353评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,290评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,331评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,020评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,610评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,694评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,927评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,330评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,904评论 2 341

推荐阅读更多精彩内容