Android自定义VIew实现卫星菜单效果浅析
一 概述:
最近一直致力于android自定义view的学习,主要在看《android群英传》,还有csdn博客鸿洋大神和wing大神的一些文章,写的很详细,自己心血来潮,学着写了个实现了类似卫星效果的一个自定义的view,分享到博客上,望各位指点一二。写的比较粗糙,见谅。(因为是在linux系统下写的,效果图我直接用手机拍的,难看,大家讲究下就看个效果,勿喷)。
先来看个效果图,有点不忍直视:
自定义view准备:
(1)创建继承自view的类;
(2)重写构造函数;
(3)定义属性。
(4)重写onmeasure(),onlayout()方法。
好了,废话不说了,准备上菜。
二 相关实现
首先是自定义的view,重写构造函数,我这里是直接继承的viewgroup,贴上代码:
public moonview(context context) { this(context,null); } public moonview(context context, attributeset attrs) { this(context, attrs,0); } public moonview(context context, attributeset attrs, int defstyleattr) { super(context, attrs, defstyleattr); }
这里需要读取自定义的属性,所以调用含三个参数的构造函数。
自定义的属性,我这里知定义了两个,一个是菜单弧形的半径,还有个是菜单在屏幕的位置,这里可以设置在左上角,左下角,右上角,右下角。代码如下:
<?xml version="1.0" encoding="utf-8"?> <resources> <declare-styleable name="moonattrs"> <attr name="mradius" format="integer"></attr><!--菜单圆形半径--> <attr name="mposition"><!--卫星菜单屏幕所在位置--> <enum name="lefttop" value="-2"></enum><!--左上角--> <enum name="leftbottom" value="-1"></enum><!--左下角--> <enum name="righttop" value="-3"></enum><!--右上角--> <enum name="rightbottom" value="-4"></enum><!--右下角--> </attr> </declare-styleable> </resources>
然后在布局文件里面引用自定义的view,配置属性:
<?xml version="1.0" encoding="utf-8"?> <com.example.liujibin.testmyview3.myview.moonview xmlns:android="http://schemas.android.com/apk/res/android" xmlns:custom="http://schemas.android.com/apk/res/com.example.liujibin.testmyview3" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent" custom:mradius="400" custom:mposition="rightbottom" > <imageview android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@mipmap/sapi_icon_add_account"/> <imageview android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@mipmap/sapi_icon_add_account"/> <imageview android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@mipmap/sapi_icon_add_account"/> <imageview android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@mipmap/sapi_icon_add_account"/> <imageview android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@mipmap/sapi_icon_add_account"/> <imageview android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@mipmap/sapi_icon_add_account"/> </com.example.liujibin.testmyview3.myview.moonview>
最后我们需要在自定义的view类中的构造函数里,获取相关的属性值:
public moonview(context context, attributeset attrs, int defstyleattr) { super(context, attrs, defstyleattr); //获取相关属性 typedarray ta = context.gettheme().obtainstyledattributes(attrs, r.styleable.moonattrs, defstyleattr,0); mraius = ta.getint(r.styleable.moonattrs_mradius,500); position = ta.getint(r.styleable.moonattrs_mposition,-1); }
做完以上的准备工作,我们就可以对组件进行测量,布局。
@override protected void onmeasure(int widthmeasurespec, int heightmeasurespec) { super.onmeasure(widthmeasurespec, heightmeasurespec); count = getchildcount()-1; angle = 90/(count-1); int count = getchildcount(); for(int i =0;i< count;i++){ measurechild(getchildat(i),widthmeasurespec,heightmeasurespec); } }
count获取按钮的数量,有一个是中心点,不参与计算,angle是每个按钮离基准线的角度,这里以90度为准,固定在这个范围里面均匀分配。
首先先把中心点固定好位置:
@override protected void onlayout(boolean b, int i, int i1, int i2, int i3) { if(ischanged){ layoutbottom(); } } private void layoutbottom(){ view view = getchildat(0); switch (position){ case -1: btml = 0; btmt = getmeasuredheight() - view.getmeasuredheight(); btmr = view.getmeasuredwidth(); btmb = getmeasuredheight(); break; case -2: btml = 0; btmt = 0; btmr = view.getmeasuredwidth(); btmb = view.getmeasuredheight(); break; case -3: btml = getmeasuredwidth() - view.getmeasuredwidth(); btmt = 0; btmr = getmeasuredwidth(); btmb = view.getmeasuredheight(); break; case -4: btml = getmeasuredwidth() - view.getmeasuredwidth(); btmt = getmeasuredheight() - view.getmeasuredheight(); btmr = getmeasuredwidth(); btmb = getmeasuredheight(); break; } btmwidth = view.getmeasuredwidth(); btmheight = view.getmeasuredheight(); view.setonclicklistener(this); view.layout(btml,btmt,btmr,btmb); }
position的值看属性就明白了,对中心点进行固定位置。并且注册点击事件。
现在开始给剩下的按钮布局,并隐藏按钮:
@override protected void onlayout(boolean b, int i, int i1, int i2, int i3) { if(ischanged){ layoutbottom(); int count = getchildcount(); for(int k = 0;k < count - 1;k++){ view view = getchildat(k+1); int childwidth = view.getmeasuredwidth(); int childheight = view.getmeasuredheight(); int childx = (int)(mraius*(math.sin(angle*(k)*math.pi/180))); int childy = (int)(mraius*(math.cos(angle*(k)*math.pi/180))); int left = 0; int top = 0; int right = 0; int bottom = 0; switch(position){ case -1: left = childx+btmwidth/2-childwidth/2; top =getmeasuredheight() - (childy+childheight/2+btmheight/2); right = childx+btmwidth/2+childwidth/2; bottom =getmeasuredheight() - (childy + btmheight/2) + childheight/2; break; case -2: left = childx+btmwidth/2-childwidth/2; top =childy-childheight/2+btmheight/2; right = childx+btmwidth/2+childwidth/2; bottom = childy + btmheight/2 + childheight/2; break; case -3: left = getmeasuredwidth() - (childx+btmwidth/2+childwidth/2); top =childy-childheight/2+btmheight/2; right = getmeasuredwidth() - (childx+btmwidth/2+childwidth/2)+childwidth; bottom = childy + btmheight/2 + childheight/2; break; case -4: left = getmeasuredwidth() - (childx+btmwidth/2+childwidth/2); top =getmeasuredheight() - (childy+childheight/2+btmheight/2); right = getmeasuredwidth() - (childx+btmwidth/2+childwidth/2)+childwidth; bottom =getmeasuredheight() - (childy + btmheight/2) + childheight/2; break; } view.layout(left,top,right,bottom); view.setvisibility(view.gone); } } }
现在我们实现点击事件:
@override public void onclick(view view) { if(ischanged){ int count = getchildcount(); for(int i = 0;i < count - 1;i++){ view childview = getchildat(i+1); int childx = (int)(mraius*(math.sin(angle*(i)*math.pi/180))); int childy = (int)(mraius*(math.cos(angle*(i)*math.pi/180))); int childwidth = view.getmeasuredwidth(); int childheight = view.getmeasuredheight(); int left = 0; int top = 0; translateanimation ta = null; switch(position){ case -1: left = childx+btmwidth/2-childwidth/2; top =getmeasuredheight() - (childy+childheight/2+btmheight/2); ta = new translateanimation(-(left+childview.getmeasuredwidth()),0,getmeasuredheight()-top,0); break; case -2: left = childx+btmwidth/2-childwidth/2; top =childy-childheight/2+btmheight/2; ta = new translateanimation(-(left+childview.getmeasuredwidth()),0,-top,0); break; case -3: left = getmeasuredwidth() - (childx+btmwidth/2+childwidth/2); top =childy-childheight/2+btmheight/2; ta = new translateanimation(getmeasuredwidth()-(left+childview.getmeasuredwidth()),0,-top,0); break; case -4: left = getmeasuredwidth() - (childx+btmwidth/2+childwidth/2); top =getmeasuredheight() - (childy+childheight/2+btmheight/2); ta = new translateanimation(getmeasuredwidth()-(left+childview.getmeasuredwidth()),0,getmeasuredheight()-top,0); break; } ta.setduration(500); childview.setanimation(ta); childview.setvisibility(view.visible); } ischanged = false; }else{ int count = getchildcount(); for(int i = 0;i < count - 1;i++){ view childview = getchildat(i+1); int childx = (int)(mraius*(math.sin(angle*(i)*math.pi/180))); int childy = (int)(mraius*(math.cos(angle*(i)*math.pi/180))); int childwidth = view.getmeasuredwidth(); int childheight = view.getmeasuredheight(); int left = 0; int top = 0; translateanimation ta = null; switch(position){ case -1: left = childx+btmwidth/2-childwidth/2; top =getmeasuredheight() - (childy+childheight/2+btmheight/2); ta = new translateanimation(0,-(left+childview.getmeasuredwidth()),0,getmeasuredheight()-top); break; case -2: left = childx+btmwidth/2-childwidth/2; top =childy-childheight/2+btmheight/2; ta = new translateanimation(0,-(left+childview.getmeasuredwidth()),0,-top); break; case -3: left = getmeasuredwidth() - (childx+btmwidth/2+childwidth/2); top =childy-childheight/2+btmheight/2; ta = new translateanimation(0,getmeasuredwidth()-(left+childview.getmeasuredwidth()),0,-top); break; case -4: left = getmeasuredwidth() - (childx+btmwidth/2+childwidth/2); top =getmeasuredheight() - (childy+childheight/2+btmheight/2); ta = new translateanimation(0,getmeasuredwidth()-(left+childview.getmeasuredwidth()),0,getmeasuredheight()-top); break; } ta.setduration(500); childview.setanimation(ta); childview.setvisibility(view.gone); } ischanged = true; } }
设置点击显示以及隐藏,并且带飘动的动画效果。
四个角落效果如下:
以上所述是小编给大家介绍的android自定义view实现卫星菜单效果浅析,希望对大家有所帮助