安卓圆形布局

这些日子一直想自己在安卓平台上写个类似苹果小白球的小程序,仗着自己会点JAVA就决定开始干了。
然后在其中需要做一个圆形的布局,于是在网上各种搜索,终究还是实现了。
觉得这个圆形布局很有意思,于是有了这篇文章,新手开写,请老师傅们多多指导。

首先我们分析一下这个圆形布局的布局,分成三个大的部分:

  1. 原点
  2. 以原点为中心承载元素的圆
  3. 需要布局在圆上的元素

那么,先从这个圆来说,我们在一个布局内(可以是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,群里面有很多大神的,而且很热情,很热心的,大家不懂的可以问的。

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值