欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android自定义VIew实现卫星菜单效果浅析

程序员文章站 2024-03-01 20:12:16
 一 概述: 最近一直致力于android自定义view的学习,主要在看《android群英传》,还有csdn博客鸿洋大神和wing大神的一些文章,写的很详细,...

 一 概述:

最近一直致力于android自定义view的学习,主要在看《android群英传》,还有csdn博客鸿洋大神和wing大神的一些文章,写的很详细,自己心血来潮,学着写了个实现了类似卫星效果的一个自定义的view,分享到博客上,望各位指点一二。写的比较粗糙,见谅。(因为是在linux系统下写的,效果图我直接用手机拍的,难看,大家讲究下就看个效果,勿喷)。

先来看个效果图,有点不忍直视:

Android自定义VIew实现卫星菜单效果浅析

自定义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实现卫星菜单效果浅析

Android自定义VIew实现卫星菜单效果浅析

Android自定义VIew实现卫星菜单效果浅析

Android自定义VIew实现卫星菜单效果浅析

以上所述是小编给大家介绍的android自定义view实现卫星菜单效果浅析,希望对大家有所帮助