Android自定义蜂窝布局

Home / Android MrLee 2017-12-20 6237

项目需要做一个蜂巢的控件,虽然不是啥难事,但是程序员其实就应该发扬拣现成的,就像没有必要每个人都写一个json解析器一样。除非写的效率不高,或者不太好用。我们可以改装,学习其优点。于是就在CSDN发现一篇文章,然后也转载到本站中,不过那个仅仅是实现绘制多个六边形。我们取其基础随便改装一下,就可以达到自己想要的效果。先看图:

这种定制的7个六边形菜单,并且实现了异形点击事件。上源码:

values\attrs.xml创建该文件

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="HiveLayout">
        <attr name="item_length" format="dimension" />
    </declare-styleable>
</resources>

目的是加一个属性,动态控制单个六边形的连长,也就是大小。接下来是布局源码

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.app.MainActivity">
    <com.app.newlight.view.HiveLayout
        android:id="@+id/id_hive"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        app:item_length="60dp" />
</RelativeLayout>

然后就是单个六边形控件类

public class HexagonView extends View {
    private float mLength;
    private float mHeight;
    private Paint mPaint;
    private Path mPath;
    private OnClickListener listener;
    //点击事件
    private RectF r;
    private Region re;
    public HexagonView(Context context, AttributeSet attrs) {
        super(context, attrs);
        re = new Region();
        r = new RectF();
        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mPath = new Path();
        TypedArray typedArray = getResources().obtainAttributes(attrs,
                R.styleable.HiveLayout);
        mLength = typedArray.getDimension(0, 60);
        typedArray.recycle();
        mHeight = (float) (Math.sqrt(3) * mLength);
    }
    public void setColor(int color) {
        mPaint.setColor(color);
    }
    /**
     * 获取边长
     *
     * @return
     */
    public float getmLength() {
        return mLength;
    }
    public void setmLength(float mLength) {
        this.mLength = mLength;
        mHeight = (float) (Math.sqrt(3) * mLength);
    }
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        if (widthMode == MeasureSpec.AT_MOST) {
            widthSize = (int) (mLength * 2f);
        } else {
//            throw new IllegalStateException("only support wrap_content");
        }
        if (heightMode == MeasureSpec.AT_MOST) {
            heightSize = (int) (Math.sqrt(3) * mLength);
        } else {
//            throw new IllegalStateException("only support wrap_content");
        }
        setMeasuredDimension(widthSize, heightSize);
    }
    //根据左上角一点 绘制整个正六边形
    private void getPath(float height, float x, float y) {
        mPath.moveTo(x, y);
        //逆时针顺序绘制六边形
        mPath.lineTo(x - mLength / 2, height / 2 + y);
        mPath.lineTo(x, height + y);
        mPath.lineTo(x + mLength, height + y);
        mPath.lineTo((float) (x + 1.5 * mLength), height / 2 + y);
        mPath.lineTo(x + mLength, y);
        mPath.lineTo(x, y);
        mPath.close();
        
        //计算控制点的边界
        mPath.computeBounds(r, true);
        //设置区域路径和剪辑描述的区域
        re.setPath(mPath, new Region((int) r.left, (int) r.top, (int) r.right, (int) r.bottom));
    }
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //正六边形的高
        float x = mLength / 2f;
        getPath(mHeight, x, 0);
        canvas.drawPath(mPath, mPaint);
    }
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (event.getAction() == MotionEvent.ACTION_DOWN && listener != null && inPath(event.getX(), event.getY()))
            listener.onClick(this);
        return super.onTouchEvent(event);
    }
    public boolean inPath(float x, float y) {
        return re.contains((int) x, (int) y);
    }
    public void setOnClickListener(OnClickListener listener) {
        this.listener = listener;
    }
    public interface OnClickListener {
        public void onClick(View view);
    }
}

定制的布局代码

public class HiveLayout extends ViewGroup {
    private HexagonView[] HexagonViews;
    private List<Integer> mColorList;
    public HiveLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
        HexagonViews = new HexagonView[7];
        for (int i = 0; i < HexagonViews.length; i++) {
            HexagonViews[i] = new HexagonView(context, attrs);
            HexagonViews[i].setId(i);
            addView(HexagonViews[i]);
        }
        mColorList = new ArrayList<Integer>();
        mColorList.add(Color.parseColor("#33B5E5"));
        mColorList.add(Color.parseColor("#AA66CC"));
        mColorList.add(Color.parseColor("#99CC00"));
        mColorList.add(Color.parseColor("#FFBB33"));
        mColorList.add(Color.parseColor("#FF4444"));
    }
    public void setOnClickListener(HexagonView.OnClickListener listener) {
        for (HexagonView h : HexagonViews) {
            if (h == null)
                continue;
            h.setOnClickListener(listener);
        }
    }
    @Override
    public LayoutParams generateLayoutParams(AttributeSet attrs) {
        return new MarginLayoutParams(getContext(), attrs);
    }
    @Override
    protected LayoutParams generateDefaultLayoutParams() {
        return new MarginLayoutParams(-2, -2);
    }
    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        int cWidth = 0;
        int cHeight = 0;
        int nCount = getChildCount();
        for (int i = 0; i < nCount; i++) {
            HexagonView childView = (HexagonView) getChildAt(i);
            childView.setColor(mColorList.get(i % mColorList.size()));
            cWidth = childView.getMeasuredWidth();
            cHeight = childView.getMeasuredHeight();
            int cl = 0, ct = 0, cr = 0, cb = 0;
            switch (i) {
                case 0:
                    cl = (int) (1.5f * childView.getmLength());
                    ct = 0;
                    break;
                case 1:
                    cl = 0;
                    ct = cHeight >> 1;
                    break;
                case 2:
                    cl = (int) (3f * childView.getmLength());
                    ct = cHeight >> 1;
                    break;
                case 3:
                    cl = (int) (1.5f * childView.getmLength());
                    ct = cHeight;
                    break;
                case 4:
                    cl = 0;
                    ct = (int) (cHeight * 1.5f);
                    break;
                case 5:
                    cl = (int) (3f * childView.getmLength());
                    ct = (int) (cHeight * 1.5f);
                    break;
                case 6:
                    cl = (int) (1.5f * childView.getmLength());
                    ct = cHeight << 1;
                    break;
            }
            cr = cl + cWidth;
            cb = cHeight + ct;
            childView.layout(cl, ct, cr, cb);
        }
    }
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
        measureChildren(widthMeasureSpec, heightMeasureSpec);
        int nCount = getChildCount();
        for (int i = 0; i < nCount; i++) {
            //求出大小即可
            HexagonView childView = (HexagonView) getChildAt(i);
            widthSize = (int) (childView.getmLength() * 5f);
            heightSize = childView.getMeasuredHeight() * 3;
            break;
        }
        setMeasuredDimension(widthSize, heightSize);
    }
}

最后就是Activity活动视窗类代码

public class MainActivity extends LActivity implements HexagonView.OnClickListener {
    private HiveLayout layout;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        layout = findViewById(R.id.id_hive);
        layout.setOnClickListener(this);
    }
    @Override
    protected void onDestroy() {
        super.onDestroy();
        System.exit(0);
    }
    @Override
    public void onClick(View view) {
        int id = view.getId();
        MLog.logInfo(String.format("六边形:%d", id));
    }
}


本文链接:https://www.it72.com/12303.htm

推荐阅读
最新回复 (1)
返回