Android 自定义View实现圆形环绕效果

之前项目中需要实现一个四周环绕中心圆形头像的效果,感觉还是自定义比较方便,于是就自己封装了一个控件去实现。先贴张图显示最终效果。

这里写图片描述

首先自定义一个View继承自LinearLayout,通过动态添加childView的方式将子控件添加到View中。思路是先添加中间圆形头像,然后添加周围的小图标。
1.实现了圆形头像的显示,可以去参考网上或github上的demo,圆形头像的外圈其实是一个View,然后再把头像这个View盖到这个View上。
2.计算好周围相邻view之间的角度,这里是要水平铺满,最多6个,所以相邻之间的角度为180/ (6 - 1) = 36度。如果是360环绕,放n个图标,则相邻之间的角度应该为360 / n 。
3.设置图标到圆心的距离r。距离要大于头像的半径加上图标的半径。
4.确定图标的坐标:控件的宽为width,高为height。假设左边第一个图标是起始位置。图标的起始角度为α= 180 - 36 * i,则它的横坐标为width/2 + cos(α)r,纵坐标为height/2 - sin(α) r。
5.设置坐标点,默认为图标的左上角顶点和右下点,如果想设图标的中心点为坐标,则左上定点x、y分别减去width/2和height/2,右下角分别加上width/2、height/2。
下面附上主要代码:

package com.ihaveu.iuzuan.cardgame.widget;

import android.content.Context;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.LinearLayout;

import com.ihaveu.iuzuan.cardgame.R;
import com.ihaveu.iuzuan.cardgame.util.MeasureUtil;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by zhouhui on 17-6-8.
 * 添加圆形子控件实现时钟环绕效果
 */

public class CircleImageLayout extends LinearLayout{

    private double mAngle = 0;//初始角度
    private int mX, mY;//子控件位置
    private int mWidth, mHeight;//控件长宽
    private int mRadius;//子控件距离控件圆心位置
    private int mCount;
    private List<CircleImageView> mCircleImageViewList;
    private CircleImageView mCircleImageView;

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

    public CircleImageLayout(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public CircleImageLayout(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        mCircleImageViewList = new ArrayList<>();
    }

    /**
     * 设置子控件到控件圆心的位置
     */
    public void setRadius(int radius) {
        mRadius = radius;
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        mWidth = getMeasuredWidth();
        mHeight = getMeasuredHeight();
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);
        initDraw();
    }

    public void initDraw() {
        mCount = getChildCount();
        for (int i = 0; i < mCount; i++) {
            View child = getChildAt(i);
            child.getWidth();
            child.getHeight();
            if (i == 0) {
                mX = mWidth / 2;
                mY = mHeight / 2;
            } else {
                mAngle = 180 - 180 / (mCount - 1) * (i - 1);
                mX = (int) (mWidth / 2 + Math.cos(Math.toRadians(mAngle)) * mRadius);
                mY = (int) (mHeight / 2 - Math.sin(Math.toRadians(mAngle)) * mRadius);
            }
            child.layout(mX - child.getWidth() / 2, mY - child.getHeight() / 2, mX + child.getWidth() / 2, mY + child.getHeight() / 2);
        }
    }

    /**
     * 初始化环绕数量半径
     */
    public void init(int count, int radius) {
        mRadius = radius;
        for (int i = 0; i < count + 1; i++) {
            CircleImageView imageView = new CircleImageView(getContext());
            if (i == 0) {
                //i为0时为圆型头像
                View view = LayoutInflater.from(getContext()).inflate(R.layout.layout_header, null, true);
                mCircleImageView = (CircleImageView) view.findViewById(R.id.iv_header);
                addView(view);
            } else {
                addView(imageView, MeasureUtil.dip2px(15), MeasureUtil.dip2px(15));
                mCircleImageViewList.add(imageView);
            }
        }
    }

}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值