这些日子一直想自己在安卓平台上写个类似苹果小白球的小程序,仗着自己会点JAVA就决定开始干了。
然后在其中需要做一个圆形的布局,于是在网上各种搜索,终究还是实现了。
觉得这个圆形布局很有意思,于是有了这篇文章,新手开写,请老师傅们多多指导。
首先我们分析一下这个圆形布局的布局,分成三个大的部分:
- 原点
- 以原点为中心承载元素的圆
- 需要布局在圆上的元素
那么,先从这个圆来说,我们在一个布局内(可以是RelativeLayout或LinearLayout)弄出一个圆,圆最大直径为布局宽高中的最小值。如下图:
最外围的深灰色长方形为我们的布局;红色圆为布局内最大的圆;
黄色小圆,为中心元素;分布四周的8个绿色的为参与圆形布局的子元素。
其中o为原点(圆心),oa为圆的半径,ab为布局的高度,也就是圆的直径。
角aor的角度为360/8;
以oa为起点,oa至or的弧度为(2 * Math.PI / 360) * (360 / 8) * 1;
为了参与圆形布局的元素不跑到我们的布局外面,
所以在计算位置时,圆的半径应该为or = oa – 元素宽度/2;所以图中灰色圆,才是我们真正计算时使用到的圆。
现在我们要计算黄色圆的XY坐标值,通过getX();getY();我们能获取到中心元素左上角的XY坐标值,即下图中m的位置;
那么中心元素元心的位置则为o.x = m.x + 中心元素宽度/2;o.y = m.y + 中心元素高度/2;
假设m的xy为{0,0},中心元素的宽度为50,高度为50,那么中心元素中心点的xy为{0+50/2,0+50/2},即中心元素中心位置的XY坐标为{25,25},同理,其他各个分布在圆上的子元素的中心位置也以此类推。
布局分析先到这儿,我们接下来直接上代码,在代码里,我们以6个元素参与圆形布局为例。
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.demo.MainActivity">
<RelativeLayout
android:id="@+id/circle_layout"
android:layout_width="300dp"
android:layout_height="200dp"
android:background="#837f7f"
android:layout_centerInParent="true"
>
<Button
android:id="@+id/btn_000"
android:layout_width="60dp"
android:layout_height="60dp"
android:text="0"
/>
<Button
android:id="@+id/btn_001"
android:layout_width="60dp"
android:layout_height="60dp"
android:text="1"
/>
<Button
android:id="@+id/btn_002"
android:layout_width="60dp"
android:layout_height="60dp"
android:text="2"
/>
<Button
android:id="@+id/btn_003"
android:layout_width="60dp"
android:layout_height="60dp"
android:text="3"
/>
<Button
android:id="@+id/btn_004"
android:layout_width="60dp"
android:layout_height="60dp"
android:text="4"
/>
<Button
android:id="@+id/btn_005"
android:layout_width="60dp"
android:layout_height="60dp"
android:text="5"
/>
<Button
android:id="@+id/client_btn"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_margin="50dp"
android:layout_centerInParent="true"
android:text="中"
android:background="@xml/shape"
/>
</RelativeLayout>
</RelativeLayout>
代码效果如下图:
我们要以”中”这个中心元素,在灰色布局类范围内,将另外6个子元素进行圆形布局,为了省事,我没有将6个子元素再做布局,直接堆一块儿了。
我们先获取布局内除“中”元素以外的其他6个子元素,代码:
/**
* 获取指定元素下的子元素
* @param parentView
* @return
*/
private List<View> getChildView(ViewGroup parentView){
List<View> views = new ArrayList<View>();
int child_count = parentView.getChildCount() - 1;//排除掉中心元素
String packageName = getApplicationContext().getPackageName();//获取当前应用包名
View view;
String id_name;
Integer id;
for (int i = 0; i< child_count; i++){
id_name = "btn_00" + i; //拼接ID名称
/**
因为懒,所以用了循环去找元素,前提是元素ID有规律
当然,也可以用getChilds()的方式获取所有子元素,再排除掉中心元素
*/
id = getResources().getIdentifier(id_name, "id", packageName);//根据ID名称获取ID值
view = findViewById(id);//根据ID找元素
views.add(view);//添加元素
}
return views;
}
找完子元素,再将这6个子元素相对“中”元素进行布局,代码:
/**
* 创建圆形布局
* @param clientView 圆形布局的中心元素
* @param views 参与圆形布局的元素
*/
private void createCircleLayout(View clientView,List<View> views){
//大圆的中心
int[] location = new int[2] ;
location[0] = (int) clientView.getX();//获取中心元素相对父级的X坐标
location[1] = (int) clientView.getY();//获取中心元素相对父级的Y坐标
//当前中心元素的X坐标
Double zeroX = Double.valueOf(location[0]);
//X坐标加元素宽度的一半,则为元素X的中心坐标
zeroX = zeroX + clientView.getWidth()/2;
//当前中心元素的Y坐标
Double zeroY = Double.valueOf(location[1]);
//Y坐标加中心元素高度的一半,则为元素Y的中心坐标
zeroY = zeroY + clientView.getHeight()/2;
/**
* 以上定下了圆的中心坐标
*/
/**
* 获取圆的半径
* 1.获取当前中心元素的父元素
* 2.计算父元素内圆的最大半径
*/
View clientViewParent = (View) clientView.getParent();
Integer radius = Math.min(clientViewParent.getWidth(), clientViewParent.getHeight()) / 2;
//参与圆形布局的元素数量
int count = views.size();
View child_view;
//定义弧度,计算子项在圆上位置时需要用到
Double hudu = 0d;
//根据子项的数量,计算每个子项间的平均角度
Double angleDelay = 360d / count;
Double tmpX;//子项X位置
Double tmpY;//子项Y位置
for (int i = 0; i<count; i++){
child_view = views.get(i);
Integer tmp_radius = radius - Math.max(child_view.getWidth(),child_view.getHeight()) / 2;
//循环计算每一个子项的弧度
hudu = (2 * Math.PI / 360) * angleDelay * i;
tmpX = zeroX + Math.sin(hudu) * tmp_radius;//计算子项的X坐标
tmpY = zeroY - Math.cos(hudu) * tmp_radius;//计算子项的Y坐标
tmpX = tmpX - child_view.getWidth() / 2; //计算子项的中心点X坐标
tmpY = tmpY - child_view.getHeight() / 2;//计算子项的中心点Y坐标
child_view.setBackgroundDrawable(clientView.getBackground());//将中心元素的圆形样式copy给子元素
child_view.setX(tmpX.intValue()); //设置子项的X坐标
child_view.setY(tmpY.intValue()); //设置子项的Y坐标
}
}
最后呢,我们将圆形布局绑定在“中”元素的点击事件上,代码:
Button button = (Button) findViewById(R.id.client_btn);
button.setOnClickListener(new ClientBtnOnClick());
class ClientBtnOnClick implements View.OnClickListener{
@Override
public void onClick(View v) {
//需要圆形布局的元素
ViewGroup circle_layout = (ViewGroup) findViewById(R.id.circle_layout);
//获取子元素
List<View> views = getChildView(circle_layout);
//对子元素进行圆形布局
createCircleLayout(v,views);
}
}
上下极简效果图
最后上下稍微漂亮点的效果图
大家若是有什么不懂或需要指正的,可以在下面评论区中留言哈,我看到后会回的,另外对android有兴趣的同学可以加我们程序员刘某人的群:555974449,群里面有很多大神的,而且很热情,很热心的,大家不懂的可以问的。